Angular2, keep models sync between components
Asked Answered
D

3

7

I'm considering moving to Angular2 from my trusted backbone (or should I say, my boss wants to play with a new toy, which is fine by me), I searched a lot online and made some tests but I can't seem to find the answer to this simple question:

Can I keep 2 models in sync between two components ? Exemple: I have a list of users on the sidebar, which is one component, and a form to edit said users in my "main page", which is another component.

The sidebar is responsible for getting its collection to display, and the form is responsible for getting its model. When the model is updated, I want the changes to be reflected in the sidebar, without going through the server again.

I know SpinJS does this and I hacked something in Backbone using events to achieve the same thing (based on model class and id), but I wonder if Angular2 has a native way of handling that ? If not, how would one go with implementing this kind of behavior ?

Thanks.

EDIT:

I added my test files in this Plunker: http://plnkr.co/edit/jIdnu68ZDMDSFJkomN3Y

First, select a hero, and click "view details", this will make an http.get request to the in-memory server to get the Hero.

Second, click on "Give sword", this will add a Weapon to the selected user. For testing purposes, instead of using the already-loaded user, I request the same one using http.get again.

When I change the name in the textbox, the name of the second instance isn't updated.

You have to imagine that I can't use the current instance of hero for whatever reasons, I want to request it again from the server.

Drink answered 15/2, 2016 at 8:59 Comment(2)
What do you mean by "When I change the name in the textbox, the name of the second instance isn't updated.". Where should it be updated? The owner of the weapon?Barmecide
Correct, since it's the same class and same id, I was wondering if there's a way to keep them in sync as SpineJS does.Drink
N
1

You can share a service between components.

@Injectable()
export class SharedService {
  someField:string;
}

@Component({selector: 'parent-cmp', providers [SharedService], ...)
export class ParentCmp {
  constructor(private model:SharedServicee) {
  }
}

@Component({selector: 'child-cmp', 
   // don't add it to providers here so it gets the same instance 
   // the parent got
   /*providers [SharedService] */, ...)
export class ChildCmp {
  constructor(private model:SharedServicee) {
  }
}

When one component changes a field in the service, the other service they are visible in the other component as well.

You can use Observable or EventEmitter to notify interested parties about changes or other events.

Nugatory answered 15/2, 2016 at 9:2 Comment(5)
Thanks for the answer! I'm already using a shared Service but the issue is that when i do UserServicer.get(id), I return a new instance with updated data from the server... Maybe the solution is to keep track of all my already fetched Users are return the same instance of already fetched ? Kinda like having every model as a Singleton. Seems like this would cause the models to never ever be garbage collected..Drink
If you put the data into the shared service you already have, this shouldn't be an issue. The shared service can manage the cache if you want to keep previously fetched data for faster response on successive requests.Barmecide
I just gave this another try and the result is the same: The second http.get() creates a separate instance of the model and when one is updated, the second is not. Maybe i'm missing something.Drink
Can you please edit your question and add the code that shows what you tried. It's impossible to discuss code that is not visible.Barmecide
I added a Plunker with the relevant files.Drink
G
1

You can use shared services to subscribe for same event in a different components. ( if you provide this service on bootstrap, it will give you same object in all components. Very important! ).

If you want to call http.get only once, and then just replay that call, you should use:

private _subject = new ReplaySubject(1);
constructor(public http: Http) {
    this.http
        .get("...").subscribe(this._subject);
}

Full, working example: https://plnkr.co/edit/G1mSXfpuYaIGXNwK5WKy?p=preview

Take a look on network panel ( chrome ), ajax call is fired only once.

Gonfalonier answered 15/2, 2016 at 10:38 Comment(0)
G
0

I think that the best way to do that is to leverage EventEmitter in a shared service. When a change is done, an event is emitted on the event emitter. Other parts of the application that have registered against it will be notified.

See this answer:

Gault answered 15/2, 2016 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.