javascript - Angular Directive - can I have an isolate scope inherit from parent? -
i trying edit angular directive written else , coming across issue. attribute directive , want watch value passed in attribute's value changes.
this works when give isolate scope , watch property using scope.$watch. using isolate scope breaks directive had scope set true needs other things (as understand means inherits parent scope).
so question is, how can inherit parent scope, watch attribute's value?
to clarify, here basic example of directive:
return { scope: { mygridsteritem: "=gridsteritem" }, restrict: 'ea', controller: 'gridsteritemctrl', controlleras: 'gridsteritem', require: ['^gridster', 'gridsteritem'], link: function(scope, $el, attrs, controllers) { ..... // need dynamically update draggable/resizable of individuaol gridster item if properties change scope.$watch("mygridsteritem.draggable", function(newval) { draggable.updatedraggable(newval); }, true); scope.$watch("mygridsteritem.resizable", function(newval) { resizable.updateresizable(newval); }, true); ..... } } this throws error due not inheriting parent scope. , if set
scope: true my error solved, watch handlers never run.
a rough outline of html:
<div gridster="gridsteropts"> <ul> <li gridster-item="getprefs(portlet.id)", ng-repeat="portlet in getportlets()"> ..... </li> </ul> </div> please me, thanks!
updated answer
i've had more of play , demonstrated 1 possible solution in code snippet below.
without using isolated scope (as caused other issues you), need getprefs(portlet.id) interpolated or parsed when directive's link function tries assign scope. without doing this, if output value of attrs.gridsteritem console you'll see it's getprefs(portlet.id), , not result of calling function.
the cleanest-looking solution came across use $parse. within link function, allows evaluate function contained in attribute @ time we're assigning scope. way it's result of function gets assigned, allows watcher functions fire correctly.
note $parse has added dependency directive declaration , passed parameter.
(function() { "use strict"; var myapp = angular.module("myapp", []) .directive("gridsteritem", ["$parse", gridsteritemdirective]); // make sure di '$parse' function gridsteritemdirective($parse) { return { restrict: 'ea', controller: 'gridsteritemctrl', controlleras: 'gridsteritem', require: ['^gridster', 'gridsteritem'], link: function(scope, $el, attrs, controllers) { scope.output = ""; //for demo'ing scope.mygridsteritem = $parse(attrs.gridsteritem)(scope); //evaluating value of attrs.gridsteritem in context of 'scope' // need dynamically update draggable/resizable of individuaol gridster item if properties change scope.$watch("mygridsteritem.draggable", function(newval) { console.log("mygridsteritem.draggable: ", newval); scope.output += "draggable updated (" + newval + ")... "; }, true); scope.$watch("mygridsteritem.resizable", function(newval) { console.log("mygridsteritem.resizable: ", newval); scope.output += "resizable updated (" + newval + ")... "; }, true); } }; } //------------------------------- //supporting mockups... myapp.controller("mycontroller", ["$scope", mycontroller]) //supporting mocks .directive("gridster", [gridsterdirective]) .controller("gridsterctrl", ["$scope", gridsterctrl]) .controller("gridsteritemctrl", ["$scope", gridsteritemctrl]); function mycontroller($scope) { var _portlets = [{ id: "1" }, { id: "2" }, { id: "3" }]; $scope.getportlets = function getportlets() { return _portlets; }; var _prefs = { "1": { draggable: true, resizable: true }, "2": { draggable: true, resizable: true }, "3": { draggable: true, resizable: true }, }; $scope.getprefs = function getprefs(id) { return _prefs[id]; } $scope.setprefs = function setprefs(id, prefname, value) { _prefs[id][prefname] = value; } } function gridsterdirective() { return { restrict: 'ea', controller: 'gridsterctrl', controlleras: 'gridster' }; } function gridsterctrl($scope) { //mock } function gridsteritemctrl($scope) { //mock } })(); <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script> <style type="text/css"> li { border: 1px solid #ccc; padding: 10px; margin: 10px; font: 0.8em arial, sans-serif; } </style> <div ng-app="myapp"> <div ng-controller="mycontroller"> <div gridster> <ul> <li gridster-item="getprefs(portlet.id)" ng-repeat="portlet in getportlets()"> <p><strong>portlet.id:</strong> {{portlet.id}}</p> <p>{{getprefs(portlet.id)}}</p> <p><strong>output:</strong> {{output}}</p> <button ng-click="setprefs(portlet.id, 'draggable', !getprefs(portlet.id).draggable)">toggle draggable</button> <button ng-click="setprefs(portlet.id, 'resizable', !getprefs(portlet.id).resizable)">toggle resizable</button> </li> </ul> </div> </div> </div> old answer:
within link function (with non-isolated scope), try this:
scope.mygridsteritem = attrs.gridsteritem; attrs param has been automatically provided link function, , should contain within collection of attributes on element directive has been used upon. attribute need, , assign scope variable matches relevant ones in $watch expressions (mygridsteritem in case, looks like).
remember angular's naming conventions mean attribute called this-is-an-attribute in html accessible thisisanattribute (snake- camel-case conversion) in javascript.
Comments
Post a Comment