In Vue.js, I have a var app = new Vue({...}); and I have a component Vue.component('mycomponent', ... where I can use such component without any issue by directly adding <mycomponent></mycomponent> in html. What I wish to do is to dynamically add those component on demand maybe after a button click or when some other such event takes place. In raw JS, I'd use document.createElement... when event fires and then do el.appendChild.. to add it into html. How would I do the same with Vue.js ?
I'm not doing anything fancy with node js. This is on a single html page with <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> in the <head>.
To do this the "Vue way" usually involves the use of v-if, v-for or <component>, depending on what you want to do:
Use v-if to conditionally show a component/element based on a condition.
Use v-for to render a list of components/elements.
Use <component> to render a dynamic component/element.
So to achieve what you described in your question, you can declare a boolean data property visible like this:
data() {
return {
visible: false
}
}
and use it with v-if to control the visibility of a component in the template:
<mycomponent v-if="visible"></mycomponent>
This requires that <mycomponent> exist in the template upfront. If you don't know what kind of component you want to show, then you can either include each possibility in the template and display the one you want based on some condition:
<comp1 v-if="comp1Visible"></comp1>
<comp2 v-if="comp2Visible"></comp2>
<comp3 v-if="comp3Visible"></comp3>
or you can use <component> together with another data property (comp) which you can set to the name of the component you want to display:
<component v-if="visible" :is="comp"></component>
What you described (document.createElement followed by el.appendChild) does not exist in Vue. Vue has a strict rendering mechanism which you need to work with; it isn't possible to dynamically instantiate components and stick them into the DOM randomly. Technically you can do comp = new Vue() as an equivalent to document.createElement and then el.appendChild(comp.$el), but that probably isn't what you want to do because you would be creating an independent Vue instance that you would have to manage manually with no easy way of passing data around.
Related
I am importing SVG elements into React component, and then rendering them as components.
How do I attach a reference to React Components that contain SVG elements from within my componentDidMount()?
Well, i don't see code example. U can try to use jQuery, when your component render will finish - this is magic stick in many situations. Just type smth like:
let element = $('#element_id');
And you will get access to its information
What is the preferred way to toggle (show/hide) a component in React? To my knowledge, there are two ways to do this.
Solution 1:
Conditionally rendering the child component inside the render() method of the parent component.
{
this.state.showUserModal ?
<UsereModal onClose={this.onModalClose} user={this.state.selectedUser}/>
: null
}
Solution 2:
Using a property at the child component which inside its own render() method returns null or the children based on the boolean.
<UsereModal show={this.state.showUserModal} onClose={this.onModalClose} user={this.state.selectedUser}/>
The second solution causes to initialize the component only once (the constructor is called once) and the first solutions do not. I am having issues with this because in need to initialize my state based on the props inside the constructor, so I am forced to use solution 2. But what are the most React way to handle this?
In both cases if the parent state or props are changed both the parent and the child components will be re-rendered. Hence there is no performance gain of the second solution. But if the child component should not be shown in the second case it will be mounted and rendered (but not shown). Taking it into account I would suggest to use the first case.
If you want to persist the DOM elements in the UI, you should go using style binding or class binding:
<UsereModal style={{display: this.state.showUserModal ? 'block' : 'none'}} />
I think the first solution is better since you do not need to initiate UsereModal component with its own state that will control should component be shown or not. I prefer also jsx notation for conditional rendering
{
this.state.showUserModal && <UsereModal onClose={this.onModalClose} user=
{this.state.selectedUser}/>
}
I use a third party library to display a table with pager :
<Grid
ref={Grid => {
this.gridRef = Grid;
}}
{...props} />
I want to modify only the pager and create a new class GridPager to override it.
In my componentDidMount I can display the element of my Grid :
componentDidMount() {
// display the Grid elements
//console.log(this.gridRef.widgetInstance.element);
// This won't work
//this.gridRef.widgetInstance.element[0].childNodes[1] = <GridPager />;
// Change the Grid pager to simple 'test'
// this.gridRef.widgetInstance.element[0].childNodes[1].innerHTML = 'test';
}
I can add simple text using innerHTML but how to add a React class GridPager ?
This is my first time I use ref and working on DOM using React.
By what I can tell what you are trying / want to do is both not possible or discouraged.
There should be no way of actively modify the React DOM like that.
childNodes elements should be read only even if you can still modify the inner HTML.
refs should be used to trigger events across different Components of the React DOM when for some reason you don't want to use the props for passing funcions.
See more here https://reactjs.org/docs/refs-and-the-dom.html#dont-overuse-refs
and here https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components
I see what and why you are trying to do this, but if you are using a component that you didn't create I don't think it's a good idea to try to modify it on the code that wraps or uses it and would instead make changes directly from the source.
I like to think of Angular components as element directives. Given a component called hero I can use it in the parent template like this:
<hero myparam="something"></hero>
I'd like to use the hero element as a component-managed container, with the component being in charge of the whole element.
EXPECTED
Here's what I hope to get out of the binding from above:
<hero id="component123" class="alien" custom="foo">text</hero>
My custom component transforms the given element and uses it as it sees fit.
ACTUAL
However, it seems the component can only render its template inside the hero element. Best I can get is:
<hero myparam="something">
<div id="component123" class="alien" custom="foo">
text
</div>
</hero>
I feel this is bad because the hero element is not actually the hero, but merly a wrapper for the actual hero. This mixes up the semantics and creates unwanted extra elements.
Is it best practice in Angular to use components as pure wrappers and putting the actual components inside?
Here's an official sample to play around with:
https://plnkr.co/edit/NKjCDS8OEngYHNrBmC5O?p=preview
I like to think of Angular components as element directives.
A component could be thought of as a special kind of directive that updates a template. If you want to change attributes, use an actual directive (attribute directive)
My custom component transforms the given element and uses it as it
sees fit.
When you talk about transforming, you want directives, not components.
I have a set of components app->page->list_container->list->item
My goal is to notify the app that click happened on item level.
If there is simple relation like parent->child I could use props and do something like: <Child onClick={this._onClick}> ... and then use this.props.onClick() to make a callback.
But what is the best native React-style receipt for doing the same trick with a tree of components? How to notify the app, that item was clicked without calling to Flux/Reflux, Elm and other supported libs?
Standard react way:
Passing onClick function as a prop down your component tree is the standard react-way of doing this.
In <app>:
<page onClick={this._onClick}>
In <page>:
<list_container onClick={this.props.onClick}>
Etcetera.
Or you could use:
<list_container {...this.props}>
To automatically pass down any prop from parent component to the child component.
In a deep tree, this can and will get quite tedious/ lot of work. React was not designed for this purpose.
React is made for (top-down) smart and fast component-tree rendering.
The frameworks for the flux pattern you mention are designed to handle the other interactive functions.
Alternative shortcut (not recommended):
A shortcut you could possibly use is to add a listener directly on the DOM, inside your <app> component, that handles the click event on the item:
In <app> component, add:
componentDidMount: function() {
var itemElementInDOM = document.getElementById('myItem');
itemElementInDOM.addEventListener('click',this._onClick);
}
And in your <item> component, give the item a (unique) id.
I would generally NOT recommend this:
In a typical react tree setup, the lower level components (like
<item>) may be rendered more than once, and then you would need
additional logic to ensure that each ID is unique.
You would also
need to add some additional smarts to make sure you remove the listener if the
item(s) in question are removed from the DOM.