I need to modify a root scope attribute from within a callback inside a directive. But the directive is in a inner scope created by a switch directive.
HTML
<div ng-app="app" ng-controller='AppController'> <p>Selected: {{ selected }}</p> <div ng-switch on="selected"> <div ng-switch-default> <p>Item: {{ selected }}</p> <custom-tag selected-item="selected" /> </div> <div ng-switch-when="New value"> <p>Worked</p> </div> </div> </div>
JavaScript
angular.module('app', []) .directive("customTag", [function () { return { restrict: "E", replace: true, template: "<input type='button' value='Click me' />", link: function (scope, element, attrs) { element.bind('click', function () { scope[attrs.selectedItem] = "New value"; scope.$apply(); }); } }; }]); function AppController($scope) { $scope.selected = 'Old value'; }
Fiddle: http://jsfiddle.net/nJ7FQ/
My objective is to be able to display "New value" in the Selected area. How can I accomplish what I am trying to do? What am I doing wrong?
Besides, as I am trying to make a component. Is there a way to do the same but with an isolated scope?
The directive scope uses prefixes to achieve that. Using prefixes helps establish a two-way or one-way binding between parent and directive scopes, and also make calls to parent scope methods. To access any data in the parent scope requires passing the data at two places – the directive scope and the directive tag.
AngularJS Scope The scope is the binding part between the HTML (view) and the JavaScript (controller). The scope is an object with the available properties and methods. The scope is available for both the view and the controller.
In an AngularJS directive the scope allows you to access the data in the attributes of the element to which the directive is applied. This is illustrated best with an example: <div my-customer name="Customer XYZ"></div> and the directive definition: angular. module('myModule', []) .
Isolated scope directive is a scope that does not inherit from the parent and exist on its own. Scenario: Lets create a very simple directive which will show the object from the parent controller.
I updated the fiddle, basically had to go to the parent to get the right "selected" variable, also used the isolate scope = to get two way binding between the value passed in and the internal model.
http://jsfiddle.net/nJ7FQ/2/
angular.module('app', []) .directive("customTag", [function () { return { restrict: "E", replace: true, template: "<input type='button' value='Click me' />", scope: {model:'='}, link: function (scope, element, attrs) { element.bind('click', function () { scope.model[attrs.selectedItem] = "New value"; scope.$apply(); }); } }; }]); function AppController($scope) { $scope.selected = 'Old value'; }
and the HTML
<div ng-app="app" ng-controller='AppController'> <p>Selected: {{ selected }}</p> <div ng-switch on="selected"> <div ng-switch-default> <p>Item: {{ selected }}</p> <custom-tag selected-item="selected" model="$parent" /> </div> <div ng-switch-when="New value"> <p>Worked</p> </div> </div> </div>
Updated the fiddle to use your original reading of the property from the attribute: http://jsfiddle.net/nJ7FQ/4/
I improved the jsfiddle a bit:
angular.module('app', []) .directive("customTag", ['$parse', function ($parse) { return { restrict: "E", replace: true, template: "<input type='button' value='Click me' />", link: function (scope, element, attrs) { element.bind('click', function () { scope.$apply(function () { $parse(attrs.selectedItem).assign(scope.$parent, "New value"); }); }); } }; }]); function AppController($scope) { $scope.selected = { 'foo': 'Old value' }; }
http://jsfiddle.net/nJ7FQ/15/
This way, the scope value, you want to change can also be an object property like selected.foo
in the example. Also, I removed the scope parameter and told the directive to always use the parent scope. And finally I wrapped the click handler into the $apply
callback (see here for example). Better would be, of course, to use ngClick
instead of the element.bind()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With