The best way to describe my problem is with a demonstration. This is how I want my directive to be used:
<my-directive my-attr="{'property': obj}"></my-directive>
Where 'obj' is an object on the scope that I want two-way binding on. The catch is I also need to get the name of the object 'obj'.
A partial solution I came up with was to pass in the name of the object ('obj') as a string and use $parse to get the object. But when this does not effect the $parent scope in the same way using scope '=' would. How can I manually write two-way binding so that changes to the object on my scope will change the object on parent scopes?
After quite some research, and with reference to the following issue , here's an extension to Scope that allows two-way binding (it is, essentially, the Angular code, only modified to work outside nodeLinkFn
):
angular.module('scopeBindExtention', [])
.run( [ '$rootScope', '$parse', function( $rootScope, $parse ) {
var extended = angular.extend( $rootScope, {} );
extended.$bindTwoWay = function( scopeName, parentName ) {
var scope = this,
parentScope = scope.$parent;
lastValue,
parentGet,
parentSet,
compare;
parentGet = $parse(parentName);
if (parentGet.literal) {
compare = angular.equals;
} else {
compare = function(a,b) { return a === b; };
}
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
lastValue = scope[scopeName] = parentGet(parentScope);
throw new Error( "Expression '" + parentName + "' is non-assignable!" );
/*
throw $compileMinErr('nonassign',
"Expression '{0}' is non-assignable!",
parentName);
*/
};
lastValue = scope[scopeName] = parentGet(parentScope);
var unwatch = parentScope.$watch($parse(parentName, function parentValueWatch(parentValue) {
if (!compare(parentValue, scope[scopeName])) {
// we are out of sync and need to copy
if (!compare(parentValue, lastValue)) {
// parent changed and it has precedence
scope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(parentScope, parentValue = scope[scopeName]);
}
}
return lastValue = parentValue;
}), null, parentGet.literal);
scope.$on('$destroy', unwatch);
}
}]);
Clients should just call:
scope.$bindTwoWay( 'childModelName', 'parentModelName' );
Can use this object syntax:
scope[ attrs.myAttr]
to access parent scope property since you aren't using an isolated scope in directive
I managed to solve my problem. My solution (in coffeescript):
$scope.$watch name, (val) ->
scope = $scope.$parent
# look up the scopes until the real object is found
while scope isnt null
if not scope.hasOwnProperty(name)
scope = scope.$parent
else
expressions[name].assign(scope, val)
scope = null
This will check up the chain of scopes and find the one that the object is defined on and modify it there. I believe this is near identical behavior to using scope: '=' in the directive definition.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.