I'm new to Angular, and cannot really find any good and clean answer to this question.
In a component I have a few buttons and a list ('li').
When a button is clicked it should create and add an instance of another component to the list. The different buttons should add different components.
I've successfully managed to add new instances via the componentFactoryResolver, but are having a hard time animating them the they are created or removed.
What would be a "correct" way (as the Angular team intended it) to dynamically add and remove components and animating it?
What you're looking for is navigation using Router.
I created a plunker here: https://embed.plnkr.co/sukXA2zRV7kEAq4MZDXY/
When you click A, an instance of Component A is created and added to the DOM and when you click B, the instance of A is gone and an instance of Component B is created.
HostComponent is the component where it has child routes defined. Notice how in the component, you don't actually reference any of these "child" components at all. The parent child route relationship is defined inside the app-routing.module.ts.
I recommend taking the time to read the Router guide from start to finish as this is one of the key aspects of developing in Angular 2:
https://angular.io/docs/ts/latest/guide/router.html
Good luck!
EDIT Added route animation for ComponentA and updated plunker link.
Related
Suppose one comes from jQuery world. If one has a component myPlugin (jQuery plug-in, for example a component showing tooltips when one hovers on specific DOM elements) it would be initiated like this:
$('.tooltipClass').myPlugin( { // options object here } )
This code will select all elements with a class tooltipClass and will apply the myPlugin on them.
In Vue.js it is different and the documentation does not really make it clear. We have
let x = new Vue({
el: '#app',
...
})
and then we read (in the documentation):
Provide the Vue instance an existing DOM element to mount on. It can be a CSS selector string or an actual HTMLElement.
But a CSS selector could return multiple elements (it won't work for multiple elements in Vue.js - as I've already tried).
So is there a way to mimic the jQuery initialization on multiple elements in Vue.js?
(I know one could achieve it manually outside the Vue.js)
The Vue.js documentation is also quite unclear on the topic. The documentation for version 3.x does not include the el option at all and it is quite hard to decide from there how to proceed in cases as in the example above.
For example one creates a popup Vue.js component and wants to show it when the user clicks on different buttons on the page. The buttons may have role='popup' attribute in the HTML and show the parameterized popup (depending on some other data-xxx attributes for example).
This is pretty standard with all javascript components nowadays. How would one achieve it with Vue.js?
If you want to attach vue to multiple elements you need to create multiple Vue instances:
document.querySelectorAll('.sampleClass').forEach(x => new Vue({el:x}));
But you need to keep in mind, that Vue works in different way that jQuery. After creating Vue instance, Vue will be responsible for creating everythink inside this element, so you shouldn't use Vue to add single behaviour to existing element, rather to create whole component with all it's behaviours with Vue.
In your example with popup you should add event listener with plain javascript and when event is fired, then create Vue instance with popup.
I followed this post to create a custom modal. Everything works as supposed except putting other Angular components inside the <div class="modal-body">.
The template and CSS of the inserted components loads but the javascript just doesn't work.
How is it possible to insert working Angular components into such a dialog?
for all the dynamically called components( those components which we are not mentioned in the template by the template selector) should be added to the entry components. If we do that Angular will instantiate the component for us.
The best practice is to mention the components in the component declarations and if there is any dynamically created components, add them into entry components. Everytime we add components to entry components it cost us the performance. try to reduced the entry components :). Hope I answered your query.
We can follow this approach Detect click outside element?
in Angular as well with HostListner.
In my component I have registered a host listener which listens on document click and hide the menu inside my component. This approach works fine with a single component.
However I am a bit concerned about the performance when the component is instantiated(in a list) 100 times each component registers document on click and do some processing to hide the menu opened from its component if any.
I can move the code outside the component list but then I need to hold references of each component to detect which one has opened menu and should be closed.
None of these two approach is perfect is there some other way to handle this efficiently as well as without leaking the component code in its parent?
Instead of setting the HostListener on the component, use it in a directive and set it on that component's wrapper. The wrapper could be an ng-container if you wish to not have template modification.
I'm new to Ember and have a leaking state problem. I have a carousel widget that displays one item at a time and allows the user to click previous/next to see each item.
Here's the simplified carousel's component:
<button {{action "nextItem"}}>Next</button>
{{carousel-item item=selectedItem}}
Clicking next changes the selectedItem property so the next item is shown.
What I've realized is that the carousel-item component isn't re-initialized every time I move to a previous/next item. The DOM is reused each time, and the component's properties are shared since it's all one instance, which means I can have leaking state.
The alternative I see is to render all the items initially, so each has its own instance:
{{#each items as |item|}}
{{carousel-item item=item}}
{{/each}}
and to hide all but the selected item using CSS. However, this option kind of feels like a jQuery hack -- seems like Ember would have a better way. And I'm only ever showing one item at a time, so I hate to have so many extra DOM nodes when I don't need them.
What is the recommended way to handle this kind of a UI, where you only need one item shown at a time but don't want to share state between items? I'd imagine I should have one instance of the carousel-item component per item, instead of sharing an instance across all of them. But it doesn't feel right to instantiate every single carousel-item at first either. And I can't imagine the Ember way is to worry too much about the DOM details myself (determining which one is shown/hidden based on a class and some CSS).
Firstly, whatever framework or library you are using, jQuery, ember, angular, react, they are just a pack of JS/HTML/CSS right? So you should think in it's way, there is no magic!
So of course 1 component will only create 1 instance. If you just changed it's property(item in your demo), it just changed the property of an instance, other properties of it will remain as it is and triggered re-render. You cannot expect more. You have to manually reset other properties.
And yes, rendering everything by {{each}} looks stupid, but think about it, how could you create a smooth carousel animation by render only one DOM? At least you need to render 3 (current, previous and next) right?
Since carousel is a common UI, I recommend you to check existing ember addons fist before you write by yourself: https://emberobserver.com/?query=carousel
If I understood your problem correctly, the willUpdate hook in Ember.Component class should help you out. I this hook you can clear up the attributes, remove DOM objects, or anything at all. This will be called each time the component is about to re-render itself.
A simple example is of form:
willUpdate() {
Ember.$(this.get('element')).empty();
},
This will clear the DOM on each re-render forcing it to redraw elements.
You can try out other hooks too and see which event will serve your need. All of them are very helpful and serve different purpose.
I'm trying to build a ReactJS component that i will release as open source that manages tabs and allows to load other components into the tabs by either create a new instance of the tab component each time you click it or reusing the same component instance until the TabView is destroyed.
I managed to create the first part of the component, and it works, but unfortunately the tabs seems always to attempt to create a new Loader component (which is responsible for either reuse an instance or create a new one.).
In the demo the companies and home count (wich can be increased by clicking) should remain the same even after changing tab and coming back. I can't save the count to the parent component because the tab will contain other complex controls and I can't keep passing the state to the parent.
How can I solve my problem? At the moment i'm saving the instance into a state property and reuse it, but it seems to not work. :/
Thanks for any futher help!
Source code: http://pastebin.com/zaqXwi4V
Online demo: http://matt93.altervista.org/demo