Angular: Nested Directives & Scope
by pmn4
HTML
<script src="https://code.angularjs.org/1.2.9/angular.js"></script>
<div ng-controller="MyCtrl">
<p>Choose an option:</p>
<!-- This is the markup I want to write -->
<radio-set ng-model="obj.prop" name="obj_prop" ng-change="thanks()">
<radio-set-button ng-value="'public'">Public</radio-set-button>
<radio-set-button ng-value="'protected'">Protected</radio-set-button>
<radio-set-button ng-value="'private'">Private</radio-set-button>
</radio-set>
<!-- end: the markup I want to write -->
<p class="message">Everything <em>looks</em> good, but as you can see below, changing your selection above does not updated the model below</p>
<pre>obj.prop: {{ obj.prop }}</pre>
</div>
<hr/>
<pre id="console"></pre>
<p class="message">The "name" attribute should be equal to "obj_prop"</p>
SCSS
.radio-set {
margin: 10px;
overflow: hidden;
.radio-set-button {
display: block;
float: left;
background-color: #f6f6f6;
&:hover {
cursor: pointer;
}
input {
position: absolute;
left: -9999px;
}
.radio-content {
padding: 10px;
}
input:checked ~ .radio-content {
background-color: #333;
color: #eee;
}
}
}
.message {
padding: 10px;
color: #000080;
font-style: italic;
}
JavaScript
var myApp = angular.module('myApp',[]);
myApp
.directive("radioSet", function () {
return {
restrict: 'E',
replace: true,
scope: {
ngModel: '=?',
ngChange: '&',
name: '@'
},
transclude: true,
template: '<div class="radio-set" ng-transclude></div>',
controller: function () {}
};
})
.directive("radioSetButton", function () {
return {
restrict: 'E',
replace: true,
require: ['^radioSet', '?ngModel'],
scope: {
ngModel: '=?', // provided by ^radioSet?
ngValue: '=?',
ngChange: '&', // provided by ^radioSet?
name: '@' // provided by ^radioSet?
},
transclude: true,
link: function (scope, element, attr) {
element.children().eq(0).attr("name", scope.name);
},
template: '<label class="radio-set-button">' +
'<input type="radio" name="name" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'<div class="radio-content" ng-transclude></div>' +
'</label>'
};
});
function MyCtrl($scope) {
$scope.obj = {
prop: ""
};
$scope.thanks = function () {
alert("Thank you for the help!");
};
}
setTimeout(function () { // just waiting a second to allow angular to do it's thing
var a, inputs = document.getElementsByTagName("input"), consol3;
consol3 = document.getElementById("console");
consol3.innerHTML += "Input attributes:";
for (var i = 0, ct = inputs.length; i < ct; i++ ) {
consol3.innerHTML += "\n";
for (var j = 0, ct2 = inputs[i].attributes.length; j < ct2; j++) {
a = inputs[i].attributes[j];
consol3.innerHTML += "\n" + a.name + "=" + a.value;
}
}
}, 1000);