Reputation: 12675
I've built a directive has an object passed to it via bindToController, with the intent of editing it. Edit was working great until I needed to cancel an edit. To undo, I needed to create a shadow copy of the original object, edit it, then copy it back or discard based on save or cancel. I've tried to achieve this in the link property of the directive, using scope.watch on the the controller property. The watch fires once, when initialized, the property is undefined because nothing has used it yet, which is expected. It never fires again though, once a real object is put into the property.
Where have I gone wrong? Should I got back to using $scope because I'm having issues getting a reference to the controller? Why is that watch only firing once?
The directive:
angular.module("ISG").directive('isgEditingFundDirective', function () {
var ctrl = null;
var isgEditingFundDirectiveController = function () {
ctrl = this; // Getting a reference to the controller so it can be used in the link function. Is there a better way to do this?
this.cancel = function () {
// Undo the edit
ctrl.fund = null;
};
this.save = function () {
// Save back to the original model
angular.copy(ctrl.shadow, ctrl.fund);
// Set to null because we aren't editing anymore
ctrl.fund = null;
}
}
var isgEditingFundDirectiveLink = function (scope, element, attrs) {
// need link so we can undo an edit
scope.$watch(ctrl.fund, function (orig, updated) {
// Trying to watch the fund property in the controller so I can create a copy for undo later.
// This never fires with a real value
angular.copy(ctrl.fund, ctrl.shadow);
});
}
return {
restrict: "E",
controllerAs: 'editFundCtrl',
templateUrl: "/angular/editfund",
bindToController: {
fund: "=fund"
},
controller: isgEditingFundDirectiveController,
link: isgEditingFundDirectiveLink
};
});
The Template:
Editing fund
Name:
<input ng-model="editFundCtrl.shadow.FundName"/>
<button ng-click="editFundCtrl.cancel()">Cancel</button>
<button ng-click="editFundCtrl.save()">Save</button>
<pre>{{editFundCtrl.fund}}</pre>
Upvotes: 2
Views: 635
Reputation: 136154
Basically you are trying to put watch on the variable which belongs to this
context of controller. $watch
function accepts string
scope variable name OR function which will evaluate on each digest cycle.
You could solve this issue just by having putting function inside watcher.
scope.$watch(function(){
return ctrl.fund;
}, function (orig, updated) {
// Trying to watch the fund property in the controller so I can create a copy for undo later.
// This never fires with a real value
angular.copy(ctrl.fund, ctrl.shadow);
});
Otherwise you could also solve this problem by having angular.bind
on this, refer this answer
Upvotes: 1
Reputation: 477
If I'm reading this right and ctrl.fund is an object, you want
scope.$watch(ctrl.fund, function (orig, updated) {
// do watch stuff here
}, true);
The true
as the second parameter forces a "deep watch", where Angular will do an angular.equals()
against the object each time it might have changed, which checks each (non-prototypical) property on the object.
For primitive types like String and Number, you'll want to have ctrl.fund
as a string, since references will be lost updates, e.g. scope.$watch('ctrl.fund', function (orig, updated)
. Angular will figure out how to parse it.
Upvotes: 0