I have an "Owner" class that has a list property of dogs
class Owner: Object {
dynamic var name: String?
let list = List<RString>()
}
I added a notification token to the list of Owner
owners?.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
updateUI()
}
The problem is, whenever the properties of RString are changed, and one of the owners has the changed RString in his list, this notification is triggered
What I want is to ignore changes that happen to RString objects and avoid triggering the notification
Is there a way to add "ignoringProperties" to the collectionChanges just like the one in objectChange? Or any other workaround?!
like getting the name of the changed property and ignoring it manually?
I have seen this code in one of Realm official videos but couldn't replicate it for collectionChanges
let token2 = state.addNotificationBlock(ignoringProperties: ["noisyProp"],
block: { change in
// handle change and avoid being notified for properties we don't care about
})
source
Thanks for your help
The .update case of the RealmCollectionChange enum passed into your update notification handler only contains the indexes of any modified objects contained in the Results returned from your query. So, as of now, it seems that preventing update notifications from being triggered by specific properties is not possible.
As an alternative, you might consider modeling your data differently by creating a separate Dog object and giving it an ownerId property and removing the dog list property from your owner object. This way you avoid update notifications from being triggered on your Owner query results when an owned Dog is modified.
Related
In my Ionic 5 project, I have created a custom component and passing the data from a Page.
HomePage HTML:
<app-userItem [inUser]="user (outSync)="syncUser($event)"></app-userItem>
Where user is.
let user = {
Name: 'Test User',
Age: 23
}
Now I want if inside component UserItem I change the value of Age, it should be synced back in the Homepage user variable. It is not happening automatically.
To Achieve this I am using the outSync event emit method for now. My question is as I am using [] to pass value of parameter inUser, shouldn't the user variable be in sync from both sides?
Now I want if inside component UserItem I change the value of Age, it should be synced back in the Homepage user variable. It is not happening automatically.
I think the reason why it's not happening automatically is because Angular compares the object identity to see if something has changed, but in your case, user === user is true even after changing user.age because the instance is still the same.
It doesn't mean the object is not being updated – it's just that Angular doesn't know that because the instance of the object is the same so as far as Angular knows, nothing have been changed.
A better approach would be if the UserItemComponent only presents the data, but doesn't change it directly (which would make it a dumb or presentational component).
For example, if that component could change both the name and the age properties, it'd be better if it just notifies the parent that those properties should be changed, and it's the parent who updates the user.
<app-userItem
[inUser]="user
(updateAge)="updateAge($event)"
(updateName)="updateName($event)"
></app-userItem>
And then the parent component would modify the data, creating a new instance of the object so that the child receives the update:
public updateAge(newAge: number): void {
this.user = {
...this.user,
age: newAge
};
}
Having following issue:
I denormalised my data structure in my Realtime Firebase Database. As a consequence of that I need to update the username in all other "posts" (in this case recipes) as well as in recipes with different authors. To do that, every time a user creates a comment on a recipe this user also creates a reference to this recipe in his user object.
Now when you change your username, it reads all those references and changes the username on this path like following (Swift):
ref.child("users/profile").child(uid ?? "ERROR").child("comments/DE").observeSingleEvent(of: .value, with: { (recipes) in
// recipe dict is a dictionary of all the references to recipes a user has commented
let recipeDict = recipes.value as! [String:Any]
// now every reference is being used to change the username at given place to the new username with variable "username"
var updateObjects: [String:String] = [:]
for i in recipeDict.keys {
updateObjects["recipes/DE/\(i)/comments/\(uid ?? "ERROR")/username"] = username
}
// Now the changes stored in the "updateObjects" variable will be applied
ref.updateChildValues(updateObjects)
})
Now this works, but the problem with this approach is, that say a recipe gets deleted, the reference doesn't get deleted (would be complicated since security rules don't allow to update another users profile so therefore not their references as well).
So that's not a huge deal for me, but since the 'updateChildValues' function creates the missing objects it is. What ends up happening is, that at the place where the deleted recipe would be, a "new" empty recipe structure without any other nodes than the comment gets created. This crashes my app and is not what I want. How can I stop this from happening?
Can you call a Multi-path update without writing data, when there is no existing structure (recipe was deleted)? Or do I need to remove all comment references and somehow give other users access to the comment references (which is tedious...)?
You could write security rules to reject a write operation to a non-existing comment if the write is just a username. For example, say that another property for each comment is the text, you could do:
"comments": {
"$commentid": {
"$uid": {
"username": {
".write": "data.parent.parent.child('text').exists()"
}
}
}
}
The problem with this is that a multi-path update performs one big check for the security rules across all these updates. So if one node was deleted, the updating of all names will fail. If that is what you want, I'd go for that.
I know you can do Model.delete() and Model.save()
Is there a way to update an existing row?
In Fluent 2.0 there is a property added to every Entity/Model:
let storage = Storage()
This object is holding additional information for each entity, if storage.exists is true it will update data when you call save() instead of trying to insert new item to database.
Reading Fluent's code, I believe it saves the fields that are "dirty".
So, you would have to do something like this:
let user = try User.find(42)
user.name = "Other Name"
try user.save()
I didn't try this, but I'll do it soon.
i'm currently using GXT 3 to display elements in a Tree.
These elements are retrieved from database and identified in the Tree by their id (by that, I mean that the id is the ModelKeyProvider of my store).
I also made it possible for users to create objects locally in the tree with the following code:
private Tree<EntityDAO, String> tree;
private TreeStore<EntityDAO> store;
int count = 1;
// instanciation and irrelevant stuff
...
EntityDAO sel = tree.getSelectionModel().getSelectedItem();
EntityDAO child = new EntityDAO();
child.setId((long) count);
store.add(store.getParent(sel), child);
count++;
tree.setExpanded(sel, true);
tree.getSelectionModel().select(child, false);
As you can see, i set a temporary id (count) to my local object.
The issue occurs when I save my object in database. A permanent id is then set to my EntityDAO but when i try to set this id to my local object to sync it with the database, it doesn't work.
I've tried to modify the child id directly
child.setId(result);
tree.update(child);
I've tried to add a copy of my object with the proper id, and then to remove my object from the tree
EntityDAO newPR = child;
newPR.setId(result);
store.add(store.getParent(child), newPR);
store.remove(child);
But the display is never updated. Any clue?
Let's discuss about the first way you tried, the update method:
child.setId(result);
tree.update(child);
From the update method API state this :
Replaces the item that matches the key of the given item, and fires a
StoreUpdateEvent to indicate that this change has occurred. Any
changes to the previous model via it's record instance will be lost
and the record will be removed. This will not cause the sort or filter
to be re-applied to the object. Overrides: update(...) in Store
Parameters: item the new item to take its place in the Store.
So basically, the update method will replace the item inside the store that have the same key with your parameter. Your data have a new key that doesn't exist inside the store, that's why it doesn't effected anything to your tree display.
Second, let's discuss the create a copy of your object and set it with the proper id:
EntityDAO newPR = child;
newPR.setId(result);
store.add(store.getParent(child), newPR);
store.remove(child);
This way actually will work, but you only have one small problem. The first line of your code actually just give you a variable that have a reference to your old object (the child object), so whenever you remove the child, the newPR also removed. You should really create a new object using the constructor, here how I think you should do it:
EntityDAO newPR = new EntityDAO();
newPR.setId(result);
newPR.setOtherProperty(child.getOtherProperty());
// just copy all property of child to newPR
store.add(store.getParent(child), newPR);
store.remove(child);
Hope this can help you.
I have CellTable with MultipleSelectionModel attached to it. After some modification of data the table has to be refreshed and new data has to be reloaded from server.
However I need to update checkboxes state for newly loaded data. So I am able to query selection boxes with selectionModel.getSelectedSet() - but now I need to find these objects in table and "check" them.
Because content of objects changes and since they are used as keys in Maps internally in GWT components- I was forced to write "wrapper" over these objects which uses only ID in equals/hashCode.
So basically I save selectedSet before firing event, then iterate over it and invoke setSelected method:
Set<T> selectedSet = selectionModel.getSelectedSet();
RangeChangeEvent.fire(table,...)
if (selectedSet != null)
for (T obj : selectedSet) {
selectionModel.setSelected(obj,true);
}
}
Is there any better approach?
This is what the ProvidesKey is for: create a ProvidesKey instance that returns the ID of your objects to be used as their keys, and pass that instance to your selection model when you build it:
MultiSelectionModel<X> selectionModel = new MultiSelectionModel<X>(new ProvidesKey<X>() {
#Override
public Object getKey(X item) {
return item.getId();
}
});
That way, you shouldn't have anything special to do with your selection model after retrieving updated data: push it to your table and it'll ask the selection model for each object whether it's selected or not, and the selection model will be able to answer based solely on the object's ID, therefore reusing the same selected set as before.