I've got a custom defined directive in angularjs. Basically what I want to happen is the user will pick a value from a select box and that will append a value to an array. This causes my custom directive to be invoked and render a new element on the screen. I want the text field that the directive generates to bind to the controller's attribute.
Html
<device-list ng-repeat="device in devices" key="device.key" display-name="device.display_name" bind-prefix="descriptions"></device-list>
Directive
angular.module('device_list_tag', []).
directive('deviceList', function() {
return {
restrict: 'E',
require: '?ngModel',
scope: {
devices: '=',
key: '=',
displayName: '=',
bindPrefix: '@'
},
link: function(scope, element, attrs) {
var deviceListElement = $(element)
var containerDiv = $('<div>')
.addClass('row')
var labelTag = $('<label>').text(scope.displayName)
.addClass('span1')
var bindField = attrs.bindPrefix+'.'+scope.key
var textField = $('<input>')
.addClass('span3')
.attr('ng-model', bindField)
containerDiv.append(labelTag)
containerDiv.append(textField)
deviceListElement.append(containerDiv)
}
}
})
Controller
function DevicesCtrl($scope) {
descriptions = {}
}
It appears as though as ng-model is local to the directive's scope, how do I make it apply to the parent? If I have a bunch of text fields on the page like
<input ng-model="descriptions.test"/>
It works works except with the fields generated by the select box.
Ok, I figured it out. It involved passing in my parent attribute as '=' (suggested by Tosh). I also had to make a call to $compile to make it recognize the ng-model directive. Here's the full code, I'm sure there's a way to do this cleaner but I'm just glad to have it working.
angular.module('device_list_tag', []).
directive('deviceList', function($compile) {
return {
restrict: 'E',
scope: {
devices: '=',
key: '=',
displayName: '=',
bindAttr: '=' // added
},
link: function(scope, element, attrs) {
console.log(scope)
var deviceListElement = $(element)
var containerDiv = $('<div>')
.addClass('row')
var labelTag = $('<label>').text(scope.displayName)
.addClass('span1')
var bindField = 'bindAttr.'+scope.key
var textField = $('<input>')
.addClass('span3')
.attr('ng-model', bindField)
$compile(textField)(scope) // added
containerDiv.append(labelTag)
containerDiv.append(textField)
deviceListElement.append(containerDiv)
}
}
})
May be you can add bindField: '='
in your scope directive definition.
And use this variable to connect to the parent scope.
Are you asking for,
1) Keep the parent scope array updated, while we edit the isolate scope form elements. If yes, i have replicated a similar scenario in this fiddle http://jsfiddle.net/W7YrZ/2/.
Summary of what i was trying to do.
1) Assign a attribute umbilical
in the ng-repeat
with the current item of the iteration.
2) Then im evaluating this attribute inside the linking function in the context of the parent scope, which gives a reference(pointer) to one of the array object in the parent scope array here profiles
.
3)Then as @Mark Rajcok says "primitives are copied by value, while objects are copied by reference". I'm binding that object got through step 2 to the text boxes in the template string.
for reasons of cleanliness of jQuery code in angular and for validation javascript, just replace the selector $
in angular.element
$('<input>').addClass('span3')
must be written
angular.element('<input>').addClass('span3')