-
Notifications
You must be signed in to change notification settings - Fork 27.5k
triggering $onChanges for updated one way binding #14378
Comments
I am interested to hear about this too. I've been using angular.copy() on the parent component to change the reference in order to trigger a $onChanges event on the child component when the value changes. This smells bad to me, but it works when I need my child component to take action on state change. |
This is indeed intended. It would be too expensive to check each object deeply for changes. Besides, in most cases, where bindings are used in a template, an "internal" change will automatically update the view. If you want to account for "deep" changes, you need to manually Note that the newly introduced lifecycle hooks are trying to stay as close as possible (and reasonable) to their ng2 equivalents. The current behavior matches that of the ng2 Closing as this is working as expected and the explanation on the SO answer is quite thorough, but feel free to continue the discussion below. |
I've written my SO answer in a proper blogpost: http://blog.kwintenp.com/the-onchanges-lifecycle-hook/ . It also proposes a way to fix the problem using ImmutableJS. |
I don't see an equivalent to |
Yeah, I've been thinking about adding something equivallent to |
@zbjornson If you're bindings are to big to efficiently copy, there might be something wrong with the architecture of your application. |
@KwintenP Thanks, interesting to discuss this. I'm new to Angular2 patterns, but I don't know how you would follow that pattern if you have multiple components relying on the same data. You don't want to duplicate the data, so that seems to preclude having multiple smart components all fetching the same data (and even if they did, how would they know when to refresh their data?). That leads to a single smart component with multiple dumb child components, but those child components need some way to observe inputs, which leads me back to the original problem... Thoughts? |
Observables ? (They seem to be the answer to any problem these days 😛 ) Assuming you do need to have a separate copy of the passed in object (which I don't think is the most common case), I wonder how else would you handle the one-to-many situation. |
Observables would work, sure. Not as tidy as magically watching objects but probably higher performance. With my initial comment, I envisioned binding to object/array references (not copies) and overriding // (in Angular 1.5)
myMod.component('foo', {
template: '...',
bindings: {
myArr: "<"
},
controller: function () {
this.doCheck = function () {
// specific logic for checking myArr changes
// maybe something like what's in ngRepeat's watch, https://github.com/angular/angular.js/blob/fa79eaa816aa27c6d1b3c084b8372f9c17c8d5a3/src/ng/directive/ngRepeat.js#L426
};
}
}); Again I'm not versed with Angular 2 and don't know if this is the correct approach, but Somewhat related, I don't know if Angular internally always checks all bindings or if it's able to check specific ones. If it can check specific ones, then likewise having binding-specific change detectors would be nice (whereas currently there's a single bindings: {
myArr: "< track by _id"
}, |
The "track by" feature is interesting. Internally it is possible to implement it (using private APIs, such as You could also use an immutable library (e.g. Immutable.js). It might in fact be easier, because you wouldn't have to manually update I'm not sure the |
Of cource, you can have your own "cheap" watchers in your child components, but it is less declarative, more error-prone and requires more boilerplate: .component('child', {
bindings: {
myArr: '<'
},
controller: function ChildCtrl($scope) {
var self = this;
$scope.$watch(getArrId, doStuffWith);
function getArrId() {
return self.myArr._id;
}
function doStuff() {
// `myArr` has been modified (even if the reference is the same).
// Do what needs to be done
}
}
}) |
Correct me if I'm wrong, but as understand it, $scope.watch is not available in angular 2 components. As such, any solution using watches seems counterproductive to the goal of creating components that will be upgradeable to angular 2. |
Just to clarify, with As far as Aside, I totally forgot that objectEquality=true in |
Just to be clear, deep-watching+ I had confused The |
Cool on the lib optimizations. Need to read more about that... Yep, It would complete the set of available lifecycle hooks for Angular 1.5 components -- Not sure on ng2, maybe: @Component()
class MyComponent {
@Input('my-arr track by _id') myArr: [MyObj];
@Input('my-obj track by version') myObj: MyObj;
} |
It might be worth investigating the TBH, at this point I would not add a cool feature in ng1 that promotes non-ng2-compatible practices. Regarding backporting If we decide it makes sense, we need to ensure that its semantics and behavior is as close a (reasonably) possible to ng2 (else it doesn't make sense). Right now there are some inconsistencies between the lifecycle hooks guide and the API docs (which are incomplete anyway), but if anyone feels like diving into the source and finding out exactly what it does (and how it relates to/affects other lifecycle hooks and component behavior), I would be interested to hear what they find out 😃 Then we can decide if it makes sense to backport it. |
I assume that should say "would NOT add"? (If so, I totally agree!) :) All sounds good, thanks for the discussion. Ticket coming up. (edit) and I'll look at the |
Correct ! Fixed 😃 |
Hi I am using angular 1.5.9, and component based approached, There is small requirement to capture old as well as new value in texbox ,I guess $watch angular not recommended to use in 1.5.x. so looking the things and came to know that $onChanges can be used for that, request to plunker example for that so i can proceed further |
I am using ngResource and having to manually trigger an update using
Should i be triggering |
@blowsie, it really depends on your requirements. You don't need a deep clone (i.e. what $ctrl.campaign = angular.extend({}, $ctrl.campaign); Note: This approach might not be enough if you are not using plain objects. |
I'm really happy with the "new" $onChanges method you can implement in a component's controller. However it only seems to be triggered when the bound variable is overwritten from outside my component, not (for instance) when an item is added to an existing array
It this intended behaviour or a bug? Is there another way of listening to updates to my input bindings, besides doing a $scope.$watch on it?
I'm using Angular 1.5.3
KwintenP has created a helpful plnkr demonstrating this issue
http://stackoverflow.com/questions/36349915/triggering-onchanges-for-updated-one-way-binding
The text was updated successfully, but these errors were encountered: