Learning Angular 2 and trying to understand when I should use a component input/output and when I should better update a service property (possibly attached with an EventEmitter if updates are needed).
I have a list of, say, tasks, and each list items shows various info and options for this list item. This list works in the way that only one list item is active, and the active one is on the top of the list. One of those options for each list item is to activate it (if it is not already active), but other components could also possibly change which is the active item.
I have a parent task component, list component and a list-item component (and some other related components), and in addition I have a task-service.
The main taskcomponent could use listcomponent (and something-realted component, many of the components used needs to know and possibly change the activeItemId), like this:
<list [(active-item-id)]=“activeItemId”></list>
<something-related [(active-item-id)]=“activeItemId”></something-related>
The listcomponent could use list-item this way (active is a pipe and also a property on item):
<list-item *ngFor=“#item of items | active”
(item)=“item”
[(active-item-id)]=“activeItemId”>
</list-item>
But since I have a task-service that contains various task related, I could on the service use the already existing activeItemId-property (that has an eventemitter), and all the various task-components could just get info (and be updated) via this property, instead of “sending” the property back and forth via various components via inputs/outputs.
When would it be appropriate to just use a service for something like this and when would it be appropriate to use input/outputs for components instead?
Got a great answer via Angular Google Groups:
Without reading your full explanation, I'd say use binding if
possible, otherwise use a shared service.
Binding is not possible when
- the two components aren't direct parent/children
- the component is added by the router
- the component is added by DynamicComponentLoader
If you share the data between several components at once it might be
easier to not use binding even when one or some of them are direct
children.
Thank you, Günter!
Related
Let's say component - TodoList need to show the list of TODO's in 2 different ways, listview and gridview .there is a switch on the page that toggles between the views. Assuming I want to keep the 2 views as different components, what is the best practice -
create TodoList component with graphql query and then pass the result of the query to TODOListView and TODOGridView components?
create TodoList component with NO graphql query and then write the same grqphql query inTODOListView and TODOGridView components (not DRY, query duplication in each component, but apollo cache will make sure that it is not called multiple times)?
good/bad with each approach?
IMHO there is no real choice, cache usage has no value as argument then no good parts with second approach.
Taking usability, UX, user centric design you probably want to keep page, sorting and filtering state while switching type of view. As an user you're expecting this kind of behaviour. This is easily available only with first solution.
Assuming I want to keep the 2 views as different components
IMHO this is wrong assumption, too. Of course you can do that but Lists are almost the same, the real difference is in item/row rendering. If this is a simple styling sets change (or adding a few elements) then even no need for using components for items, just conditional rendering. You can change/refactor it later.
Utilizing item components you can have additional abstraction layer and more complex use cases available. With passed down (into items) switching type handler I was able to change it (gloablly) from simgle item level or change locally item view type - mixed element list.
I'm wondering what would be the best way to treat the following scenario:
I have a component (PeopleSelector) that loads objects of type Person and allows the user to select some of them. The data load logic (using a REST service) is proprietary of the component, so it should be private to it. The selected persons are included in an array of Person objects, included in a double bind.
In a container page, this component will be used, and the selected persons must be set (using an array of ids received from other service).
Problem is, the parent controller may receive the list of ids before the available persons are loaded in the child component (as services are asynchronous), so it cannot obtain the list of persons filtering the available objects in the child component.
So, how should I implement this use case?
Thanks
What's the best way to handle a case where multiple components are using one store (which is populated by API calls in an action creator), but each component may need to access different sets of data without effecting the other. I.e.: two table components display data from the WidgetStore; one table wants all widgets, the other only displays widgets whose name contains "foo" (this would be based on user input). The table being queried via the API has tens of thousands of widgets, so loading them all into the store and filtering from the store isn't practical. Is there a Flux architecture (like Redux) that already has a way of handling this type of thing?
The simplest way is to just create a parent component and selectively hand off data, using a pluck or selector function, to each of the children.
For the more general answer for yourself going forward... if you follow something along the lines like redux there is already proven patterns which will help you understand passing complex data down.
Let's say I've got a UserComponent that shows some user details. Using the React+Flux+Immutable architecture, I can tell this to listen for UserStore changes so it can update itself.
Now if I want to show a list of users, I may want to reuse this component and use it within a UserListComponent. This will also need to listen to the UserStore in order to add / remove items as they're added / removed from the backing store.
If I have a list of 100 users, this'll cause 101 components to be listening to the UserStore, and arguably 100 of those (the items) don't need to be because the list is doing so on their behalf. Is there an approach I should be taking to design around this situation? Or is it not something I need to worry about?
I'm still very new to React, and the samples I've been following don't account for this - the TodoMVC for example has TodoItems that don't listen to the store, and rely on the list to do so on their behalf. However, this prevents them being used outside of a list which seems a bit limiting.
You can put state in a common ancestor/owner component (your list), and each sub-component (user detail component) will derive/borrow its state from that common ancestor -- as a prop.
For good performance, you can use Immutable in concert with the componentShouldUpdate function.
I'm really new to the MVC pattern in Ext.
I have a tabpanel with multiple instances of the same component (let's call it product), each should call the server when it's opened, with an id parameter.
Right now, in order to create these tabs - I use this in the Product controller
Which creates a new instance of a view, but I feel like it's really incorrect.
createMainView: function (opts) {
return Ext.widget("productDisplay", opts);
}
I call it from my "main" controller, like this:
var tab = this.application.getController("Products")
.createMainView({ productId : id, closable: true })
tabs.add(tab);
tabs.setActiveTab(tab);
What's the correct way to properly use multiple instances of a view, each having an instance of one store and behavior (via the controller).
Can I use one named store for them (with a js file under app/store/product.js)?
Should I manually call load on the store from the controller (to pass the productId), or is there a nicer way?
It's kind of very broad and interesting question which require big and thorough explanation (which you can find btw on the Sencha.com in their guides and manuals). I would like highlight couple points so you have something to start with:
Stores are usually global objects. You don't keep two instances of one store in general. You can use filtering (local or remote) if you need to present information from the that store in several different views. The only time you would need to clone store is if you want to present different information from that store in 2+ different views at the same time.
Controllers are usually spawned by main application object. You don't have to do anything special - just list them in the controllers: [] property. And then spawed when application is launched (before their views are created and rendered). Keep that in mind.
If you have modal view - it's ok to create it manually and either re-use it or destroy and re-create later. You can add filtering and loading to controller which creates these views. And you can re-use same view/controller objects for different tabs if you want.
If your views are presenting one instance of an object (like one product is displayed on each tab) - don't attach stores to those views. Just pass them individual model (record).
I would recommend creating the stores that relate only to that view instance inside of the view's initComponent method.
Your controller's control handlers should be coded in a way that they can differentiate which view dispatched the event. This should not be too difficult because almost all view events contain a reference to the component which fired the event. You could then use the relative query selectors, e.g.: myEventFiringComponent.up('anotherComponent') or myEventFiringComponent.down('anotherComponent') to get a handle on a different component in the same view if you need to.
Please see this post for a full explanation.