Create component in template from data variable - vue.js

I have multiple components that take same props. I want to use those components in template in such a way that I don't use multiple if-else statements in my template. I created an object in my data and paired my components with string keys. Is there a way to call those components in template with that object ? My data object looks something like this:
componentMap:{
"testComponent1":TestComponent1,
"testComponent2":TestComponent2,
},
For example, if I give "testComponent1" as key, then in template it should use TestComponent.

Use the component tag.
<component :is="componentMap['testComponent1']"></component>
See the Docs

Related

Can a component be found using its key?

Does Vue test-utils support looking for components in a list using their key? If not is there other ways of looking for components that are generated in the form of a list in vue?
You can't query a component using the key in the findComponent() method.
But you can fetch all components within your list, and then filter them like a regular array.
Just provide the right condition to find the item you want (usings its props, attrs or whatever)
const items = wrapper.findAllComponents(MyListItem)
const foundItem = items.wrappers.find(listItem => list.props('id') === 'theIdILookFor')

Vue js - is that right to put all my code in watch?

I Have component A and Component B
in component A i have an API call.
when i passing info to my component b:
<B :structuresMetaData="structureTree"></B>
Inside mounted the variable structuresMetaData the length is 0
and inside the watch the length is 1.
my issue that mounted appear before the watch.
is it would be right to put all my code in watch ? if not what is the solution ?
It looks like structureTree is being changed after <B> is created/mounted.
You have two options depending on your use case:
The first option is to defer the creation of <B> until your data is loaded. This way you don't need <B> to watch for changes to the prop and the prop will be fully populated in the created/mounted hook. This is the simpler approach.
Assuming structureTree is initially an empty array:
<B
v-if="structureTree.length > 0"
:structuresMetaData="structureTree"
/>
created() {
// this.structuresMetaData is a non-empty array here
}
I usually initialize my data with null so that I can distinguish between "not loaded" and "loaded" (where "loaded" can actually be an empty array if the data I fetched from the API was empty).
The second way is using a watcher in <B> to react to changes to the prop. You will need to do this method if the bound prop might change multiple times and you need <B> to update in some way to that change.
watch: {
structuresMetaData(value) {
// React to the change, load secondary data, etc
}
}
What exactly are you doing in <B> that requires a watcher? It's best to avoid explicit watchers if you can avoid them because it usually means you are copying data around and it gets messy when you don't have a single source of truth. Use pure computed properties whenever you can if you just want to transform the data in some way.

Vue2 component as <vue-component>value</vue-component>

It is possible to pass a value to the component between the component tags?
Example: in a component to format value to money, I created as :
<vue-component value="50" />
and it display
$ 50,00
Now, just for curiosity, it is a way to call the component like these:
<vue-component>50</vue-component>
Read about slots: vuejs.org/v2/guide/components-slots.html
Fe: <template><h1><slot/></h1></template>
You can access ita value via: this.$slots.default[0].text
The fact that it's possible doesn't mean that you should do it. Actually, on the contrary. Props have multiple advantages (such as marking as required, default value, validators and many more) but in thr first place they are standardised way of passing data to children components every vuejs developer will understand.

VueJS Component Input Sync

I want to create components which have input which two-way bind to the local scope of the component.
Without a component, I would create a new Vue instance and then set my data to what I need. Then using v-model, bind an input to that data and it can be manipulated from the input.
However, converting the same code to a component, I cannot for the life of me get any input in a component to bind to its data. I have tried props, :data.sync, data attributes but no matter what I have tried, the input within a component does nothing.
I have created a JSFiddle to illustrate this:
https://fiddle.jshell.net/f0pdmLhy/2/
What I would like to happen is the input in the component to two way bind to the err variable, just like the non component version underneath.
How would I accomplish this?
I basically want to create components that I can instansiate with ajax data and then populate the inputs. The inputs could then update the data and I can use a save method to send the data to the server. Can this even be done using components?
So there are a couple of things:
The external resource you were using was somehow faulty. I've used
jsfiddle default Vue instance and it works fine.
When you declare a component, you should not define the data as an object, but as a function returning an object. Read here: https://vuejs.org/guide/components.html#Component-Option-Caveats
A working example here: https://fiddle.jshell.net/by4csn1b/1/
Yes, with components, the reactivity can be accomplished just like with an instance.
One catch with components, is that data must be a function that returns an object.
Also, to maintain the two way binding, use v-model in your input.
Vue.component('ii', {
template: '<span>{{err}}</span><input type="text" v-model="err"><hr>',
data: function () {
return {
err: 123
}
}
})
Fiddle: https://fiddle.jshell.net/f0pdmLhy/25/

Pass an object to a widget in template

I have a Dojo UI widget that has a widget embedded within it. I need to pass an object to this embedded widget for it to set itself up correctly, but I'm not sure how to do it.
I have been templating in the embedded widget in the template for the wrapper widget, for example:
...<div class="thing"
data-dojo-type="mycompany.widgets.ComplexEmbeddedWidget"
data-dojo-props="stuff: '${stuff}'"></div>...
but this doesn't seem to work, I guess the data is passed as a string maybe?
I'm pulling out this data by setting it to a property in the embedded widget and then referencing it in my postMixInProperties function.
Doubtless this is the wrong approach, what should I be doing to set up an embedded widget such as this?
I think if you are going to use this approach, you want to convert the javascript object json before it is passed to the templated embedded widget.
You can easily do this by requiring 'dojo/json' and doing
this.stuff=jsonModule.stringify(this.stuffAsObject);
As you have already discovered, if you are setting more complex properties, programmatic instantiation is probably the way to go.
If your mycompany.widgets.ComplexEmbeddedWidget is desperate to have the object 'stuff' set allready once it is initialized (in constructor), then im not sure this approach will do, however a simple fix could be removing the ' quotes around ${stuff}?
What happens is basically that you derive the widget with dijit/_TemplatedMixin. This in turn, during buildRendering, calls _stringRepl on 'this' (the widget). I am not completely certain of the flow, since youre working with WidgetsInTemplate..
lets as example, set a widgets attribute to an array via markup:
<div
data-dojo-type="dijit.form.Select"
data-dojo-props="options:[ 'val1', 'val2']">
</div>
As you see, no quotes around the value - or it will render as a string. Lets then change your ComplexEmbedded template to
dojo.declare("exampleName", [_WidgetsInTemplateMixin, _TemplatedMixin], {
templateString: '<div class="outerWidgetDomNode">
...
<div class="thing"
data-dojo-type="mycompany.widgets.ComplexEmbeddedWidget"
data-dojo-props="stuff: ${stuff}"></div>
...
'
});
To instantiate the ComplexEmbeddedWidget.stuff with an object, this needs to be a string. _Templated uses dojo.string.substitute, which probably would fail if given deep nested object.
Markup example:
<div data-dojo-type="exampleName" data-dojo-props="stuff: '{ json:\'Representation\', as:\'String\'}'"></div>
Or via programmatic
var myObj = { obj:'Representation', as:'Object' };
var anExampleName = new exampleName({
stuff: dojo.toJson(myObj) // stringify here
}, 'exampleNode');
Lets know how goes, ive been wanting to look into the presendence of flow with this embedding widgets into template stuff for a while :)
You can programmatically insert widgets. This seems to be be the way to go if the inserted widget requires JavaScript objects to be passed to it.