Emberjs - Temporary disable property changes notification - binding

Is there any simple way to achieve a temporary disabling of notifications of an object property or properties?
I know you can defer them with beginPropertyChanges() and endPropertyChanges() but I don't want those changes to be notified at all until I explicitly enable them.
Thank you in advance.
Use case:
I have to set a property of an object (A) with another object (B). Properties of B are being observed by several methods of other objects. At some time the B object's data gets cleared and the observers get notified, later an HTTP response sets them with something useful. I would not want the observers get notified when clearing the object because the properties values are not valid at that moment.

Ember doesn't support suspending notifications. I would strongly suggest against toying with the private APIs mentioned in the above comments.
I wonder why you bother clearing the object's data prior to the HTTP request? Seems strange.

Using a flag will cause the computed to still trigger.
The best I've come up with is to override the computed with the last known value. Later you can enable it by setting the computed property definition again.
let _myComputedProperty = Ember.computed('foobar', function() {
let foobar = this.get('foobar');
console.log('myComputedProperty triggered >', foobar);
return '_' + foobar + '_';
});
Controller.extend({
turnOffComputed: function() {
let myComputedProperty = this.get('myComputedProperty');
this.set('myComputedProperty', myComputedProperty);
},
turnOnComputed: function() {
this.set('myComputedProperty', _myComputedProperty);
}
})
Full example: Conditional binding for a computed property

This is an old question, but it appears high in Google search for suspending observers, so I would comment.
There are evident use cases for such a feature, for example, an enum property of an object is represented by a list box and the object may change. If the list box is used to request property changes from the server and to set the new value on success, the natural way to do things is to use a controller property with the list box, set that property to the object property when the object changes, and observe it to make requests to the server. In this case whenever the object changes the observer will receive an unwanted notification.
However, I agree that these use cases are so diverse that there is no way Ember can support them.
Thus, a possible work around is to declare a variable in the controller and use it whenever you change a property so that you react only to changes made by the User:
doNotReact: false,
updateManually: function() {
this.doNotReact = true;
Ember.run.scheduleOnce('actions', this, function() {
this.doNotReact = false;
});
............
this.set('something', somevalue);
............
},
onChange: function() {
if (this.doNotReact) return;
...............
}.observes('something')
The value of doNotReact will be reset after the observer gets a chance to run. I do not recommend to reset the stopper variable in the observer since it will not run if you set the property to the same value it already has.

Related

How to run a specific method when props changes in Svelte3?

I'm building an autocomplete text field component. We will show popup of items filtered based on what users type. It is going to be async, I will get the details from the server and do some filtering based on the text typed in the field.
So here, I have run this filtering logic whenever I send new data to the component.
I come from angular, there we used to have ngOnChange(). Is there something similar available in svelte3.
Right now, I'm filtering by calling the method from outside by binding bind:this. I don't feel like this is a correct approach.
https://github.com/manojp1988/svelte3-autocomplete/blob/master/dev/App.svelte
Without stores, using a prop
Just using a prop:
export let search = '';
....
$: if (search !== '') { // make it react to changes (in the parent)
doSomeThing(search);
};
Stores
Svelte also has stores. A store is an observable object which can be observed everywhere even beyond you project with RxJS.
Example:
const unsubscribe = search.subscribe(s) => {
doSomeThing(s);
});
onDestroy(unsubscribe);
In another component you can use search.set('Hi');
But looking forward for other solutions to handle these kind of changes in parent <-> child components or calling child Component methods.
From child to parent we can fire events.
But from parent to child ...? we can use a store or Component bind:this or ..? but ....

How to force a fetch in Relay modern

My top-level component includes a settings dialog that includes the user's credentials. When a change is made in that dialog and the dialog is dismissed (state is changed to dialogOpen=false), I want to force a new fetch from the server since the credentials may have changed. In Relay classic, the top-level component includes a Relay.RootContainer and so I just passed forceFetch=true to that RootContainer. In Relay modern, my top-level component includes a QueryRenderer. So how do I force the refetch in this case?
I found this issue, https://github.com/facebook/relay/issues/1684, which seems to indicate that the QueryRenderer always refetches, but this doesn't seem to be the case in my testing. At least, I'm not seeing my fetchQuery get called after the state change/refresh when the settings dialog is closed. I think I'm probably not completely understanding the statements in that issue.
Can anyone clarify?
OK, I think I figured out my disconnect here. In checking the source for QueryRenderer (don't know why I didn't do this in the first place), I saw that a fetch will occur if props.variables changes. So I just defined a boolean instance variable called refetch and flip its value when my dialog is dismissed:
<QueryRenderer
environment={environment}
query={query}
variables={{refetch: this.refetch}}
Since this doesn't seem to well documented, I'll mention here that QueryRenderer will re-fetch when any of the following conditions is true:
current query parameter is not equal to the previous query parameter.
current environment parameter is not equal to the previous environment parameter.
current variables parameter is not equal to the previous variables parameter.
You can use the retry function that's passed to QueryRenderer's render.
<QueryRenderer
environment={environment}
query={graphql`
query MyQuery($exampleUserId: String!) {
user(userId: $exampleUserId) {
favoriteIceCream
}
}
`}
render={({ error, props, retry }) => {
// Here, you could call `retry()` to refetch data
// or pass it as a prop to a child component.
return (
<IceCreamSelectionView refetchData={retry} user={props.user} />
)
}} />

RxSwift - Class property's binding

I have an question about binding:
I have an array of objects of my custom class: Array. Every object can be updated (change his properties value) in bg.
Also I have separated Controller, which take and store one object from list as variable and can update it (object still the same, so in list it will be updated too)
Is there any way to bind all object.property -> UILabels on Controller in way, when property changes automatically call label update?
Of course, there are multiple ways how to do it, but from your description I would use some kind of subject (because u said there will be changes in background so you will probably need hot observable )....For example Variable or PublishSubject. So you can crate
let myArrayStream: Variable<[MyObject]> = Variable([])
you can pass this variable as dependency to wherever you want, on one side you can subscribe to it, on the other side you can update it's value.

Identifying old and new values on changed objects with NSManagedObjectContextWillSaveNotification

I am trying to track changes to objects in a core data context, tracking the name of properties that have changed along with the old and new values.
I've registered for NSManagedObjectContextWillSaveNotification to receive a notification when a save is about to occur, and can pull out the inserted/updated/deleted objects from the context... I can then see the changed values using .changedValues.
However, I am having difficulties retrieving the old values...
As an example, I have an object that tracks a position, and so one of the changes comes back with:
po [obj changedValues]
{
originX = 260;
originY = 180;
}
This gives me the new values for the properties that have changed on the object. To try and get the old values, I'm then using changedValuesForCurrentEvent, which according to the docs should return
"a dictionary containing the keys and old values of persistent
properties that have changed since the last posting of
NSManagedObjectContextObjectsDidChangeNotification"
However, when I try this, it is coming back empty...:
po [obj changedValuesForCurrentEvent]
{
}
How can I capture the old and new values?
You're mixing up your notifications. NSManagedObjectContextObjectsDidChangeNotification gets called any time you change values on a managed object, even though you haven't saved changes yet. NSManagedObjectContextWillSaveNotification gets called later on when you save. So the sequence is:
You change some attributes --> NSManagedObjectContextObjectsDidChangeNotification is posted, and you can use changedValuesForCurrentEvent to see what changed.
Later, you save changes. NSManagedObjectContextWillSaveNotification is posted. You can call changedValuesForCurrentEvent, but it's not helpful because it returns changes since the last did-change notification. There are no changes since the last did-change notification. If there were, you would have received another one. That method is documented to be useful on a did-change notification, not on a will-save notification.
If you want the old values and you want to get them when the will-save notification is posted, you have a couple of options:
Listen for NSManagedObjectContextObjectsDidChangeNotification. Cache information about changes in some collection object (probably NSDictionary). Then when NSManagedObjectContextWillSaveNotification happens, look up those changes, process them, and clear the change cache. OR...
When you get NSManagedObjectContextWillSaveNotification, create a second local managed object context. Since this is a will save notification, you can still fetch the old values. So, fetch each object that's getting saved and compare the before and after values to see what's different.
Although this question is 4 years old, Eddie's answer was very helpful. I made a little change to his answer. All the credits goes to him.
object.setValuesForKeys(object.committedValues(forKeys: object.changedValues().map { $0.key }))
I know this question is old, but there is a better way than the accepted answer. You can access the previous values via committedValues(forKeys:) in combination with changedValues(). There is no need to handle NSManagedObjectContextObjectsDidChangeNotification or to create another managed object context.
Here is some sample code that I use:
// For some reason, the Swift compiler chokes on the type of object.changedValues().keys.
// It should be of type [String], but it complains that it is of type `Dictionary<String, Any>.Keys`
// which is useless. Ah, the joys of Apple programming...
// Work around that like so:
var changedKeys = [String]()
for (key, _) in object.changedValues() {
changedKeys.append(key)
}
let oldData = object.committedValues(forKeys: changedKeys)
Sounds like you should call "changedValuesForCurrentEvent" only when you receive your "NSManagedObjectContextWillSaveNotification" notification.
And if "changedValuesForCurrentEvent" still returns a null dictionary or object, check to see if the notification had anything useful in it's "userInfo" dictionary itself. It also may be that there has not been a NSManagedObjectContextObjectsDidChangeNotification" posted, like you posted from the docs up there.

Cancel/Block the save of a domain object based on some criteria?

i have a need to block or cancel a save of a domain object based on some property.
Can this be done in a constraint?
Example:
An 'Order' domain object has a state of 'invoiced' then the order should not be able to be updated anymore..
Any suggestions on how to tackle this?
I see no reason why you couldn't simply use a constraint for this (as you suggested). Something like this should do it
class Order {
String state
static constraints = {
state(validator: {stateValue, self ->
// only check state if this object has already been saved
if (self.id && stateValue == 'invoiced') {
return false
}
})
}
}
If for some reason you can't use a constraint, here are a couple of alternative suggestions:
Meta-Programming
Use Groovy's method-interception capabilities to intercept calls to save(). Your interceptor should only forward the call to the intercepted save() if the order does not have an invoiced state.
There are some good examples of how to do this in the Programming Groovy book
GORM Events
GORM provides a number of events that are triggered during a persisted objects lifecycle. It may be possible in the beforeUpdate or beforeValidate events to prevent updating the object (I guess throwing an exception would work)

Resources