I've been trying to pass a prop in a component's template.
I think I'm missing some points here, and I didn't start to include my components in single files yet.
app.js
Vue.component('chat-response', {
props: ['response', 'senderClass'],
template: '<div>From {{ senderClass }} : {{ response.text }}</div>'
})
var app = new Vue({
el: '#app_chat',
data: {
responseList: [
{ id: 0, text: 'Response 1', type: 'Owner' },
{ id: 1, text: 'Response 2', type: 'Other' },
{ id: 2, text: 'Response 3', type: 'None' }
]
}
})
page.html
...
<chat-response v-for="response in responseList"
v-bind:key="response.id"
v-bind:response="response"
v-bind:senderClass="response.type"></chat-response>
...
Output :
From : Response 1
From : Response 2
From : Response 3
As we see, senderClass won't show up. I've tried different methods and only got errors that I could understand after reading around.
I don't wish to use response.type instead of senderClass because in the meantime, I'm setting senderClass after mounted with a real css class.
Maybe it's my approach that's completely wrong, could you give me some hints ?
I think the name of your property is wrong. Just change in page.html v-bind:senderClass="response.type" to v-bind:sender-class="response.type"
http://jsfiddle.net/eywraw8t/310360/
HTML attribute names are case-insensitive. Any uppercase character will be interpreted as lowercase. So camelCased prop names need to use their kebab-cased equivalents.
Apart from what Jns said You could get rid of v-bind altogether and just use :varibaleName for bindings.
Link to fiddle
https://jsfiddle.net/50wL7mdz/654614/#&togetherjs=J9vgbNaR7m
Related
I am using vuetable-2 and somehow the formatter for my fields does not work. The frontend for my isCoach field still shows as 1 but based on the formatter set, it should instead return Active.
Template
<vuetable
ref="vuetable"
api-url=""
:query-params="makeQueryParams"
:per-page="perPage"
pagination-path
data-path="Data"
:reactive-api-url="true"
:fields="fields"
:row-class="onRowClass"
#vuetable:pagination-data="onPaginationData"
#vuetable:cell-rightclicked="rightClicked"
>
Data
fields:[
{
name: "isCoach",
sortField: "isCoach",
title: "Coach",
titleClass: "",
dataClass: "text-muted",
width: "5%",
formatter: (value) => {
return value === '1' ? 'Active' : 'Disable'
}
},
]
Documentation: https://www.vuetable.com/guide/fields-definition.html#field-options
I found the solution. Apparently formatter doesn't work. Changing it to callback solved my issue.
in Category.vue I have the following line of code from the default files from storefront
{{ $t('{count} items', { count: getCategoryProductsTotal }) }}
https://github.com/vuestorefront/vsf-default/blob/master/pages/Category.vue#L62
but it renders as "{count} items", not with the actual value of the count var.
however, if I added {{getCategoryProductsTotal}} outside the translation statement I get the actual value for the total count.
I suggest you to insert the count inside the object like below
i18n: new VueI18n({
locale: 'en',
messages: {
en: { hello: 'hi there', count: '{val} items' },
cn: { hello: '你好', count: '{val} 项目' }
}
})
and then in template use it like
{{ $t('count', { val: getCategoryProductsTotal }) }}
Note:
getCategoryProductsTotal should be a computed property.
if that's a method then use it like
{{ $t('count', { val: getCategoryProductsTotal() }) }}
But always prefer computed for these use cases
You should specify the version of VSF you are using so we could reproduce it locally. E.g. I've just created a new project with VSF1.12.3 (the newest stable version) and vsf-default theme (1.12.1) and it works perfectly fine.
I need to update some Array data in my VueJS component which is rendering as a list in the template via v-for.
When I update the whole Array, I see that the list updates in the DOM. But, if I update only an index, the list does not update.
Here are the two relevant methods:
methods: {
loadOnlyOneIndex: function() {
this.data[0] = {
title: 'Hello error',
slug: 'hello',
desc: 'will not work'
};
},
loadEverything: function() {
this.data = [{
title: 'Hello new title',
slug: 'hello',
desc: 'this will work'
}, {
title: 'Hello new title 2 !',
slug: 'hello2',
desc: 'really work'
}];
}
}
Here is a fiddle.
From the documentation:
Due to limitations in JavaScript, Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
To get Vue to react to the change of an array's index, use the Vue.set() method.
In your case, you should use Vue.set(this.data, 0, newValue) in your loadOnlyOneIndex method.
Here's a working fiddle.
Every Vue instance also has an alias to the Vue.set method via vm.$set (where vm is the Vue instance).
So, you could also use this.$set(this.data, 0, newValue) in your loadOnlyOneIndex method.
This is helpful when using Single File Components, or anywhere where you don't have a direct reference to the Vue object.
I'm working with react-select, to add a multi-select control in my web-app. http://jedwatson.github.io/react-select/
I'm looking for a good example to inject mobx observables into the control.
The first challenge I have is initialising the options in an async way (options are fetched from server, but after that I want regular filtering to apply, no need for async-options).
Any good examples out there?
import Select from 'react-select';
<Select
multi
disabled={this.state.disabled}
value={this.state.value}
placeholder="Select your favourite(s)"
options={this.state.options}
onChange={this.handleSelectChange}
/>
As noted in MobX documentation, due to limitations in ES5, ObservableArray still has some quirks. react-select is one of those libraries that don't work with ObservableArray out of the box. There are 2 ways to solve this.
Method 1
you already have an observable array with label and value
#observable myOptions = [
{label: 'foo', value: 123},
{label: 'bar', value: 345}
]
then you can use the ObservableArray's .peek() method to return a regular array for read-only purposes
<Select
options={this.myOptions.peek()}
onChange={this.handleSelectChange}
/>
Method 2
You have the observable array in some other format, returned from server. This is a more common case, actually.
#observable peopleData = [
{name: 'foo', _id: 123, address: 'fooville'},
{name: 'bar', _id: 345, address: 'barville'}
]
in this case, you can create a #computed value, which also returns a plain array:
#computed get peopleOptions() {
return this.peopleData.map(x => ({ label: x.name, value: x._id })
}
and connect the Select component to the computed value, which will auto-update each time new data from server are fetched.
<Select
options={this.peopleOptions}
onChange={this.handleSelectChange}
/>
in both cases, this.handleSelectChange should just update the original data.
I have a VueJS address lookup component.
Vue.component('address-lookup',
{
template: '#address-lookup-template',
data: function()
{
return {
address: {'name': '', 'town:': '', 'postcode': ''},
errors: {'name': false, 'town': false, 'postcode': false},
states: {'busy': false, 'found': false},
result: {}
}
},
methods:
{
findAddress: function(event)
{
if( typeof event === 'object' && typeof event.target === 'object' )
{
event.target.blur();
}
$.ajax(
{
context: this,
url: '/lookup',
data:
{
'name': this.address.name,
'town': this.address.town,
'postcode': this.address.postcode
},
success: function(data)
{
this.states.busy = false;
this.states.found = true;
this.address.name = data.name;
this.result = data;
}
});
},
reset: function()
{
this.states.found = false;
this.result = {};
}
}
});
Inside my template I've then bound the result like so:
<p>{{ result.formatted_address }}</p>
There is some extra data returned within the result (like a twitter handle) that isn't part of the address lookup template, and occurs on a separate part of the form. For reasons relating to how my form is structured I can't include these inputs within the same template.
I found a way to bind those inputs, although it felt somewhat 'hacky'.
<input type="text" name="twitter" v-model="$refs.lookupResult._data.result.twitter">
That all works fine.
My problem is that the form is included as part of a larger template sometimes in the context of creating a new record, sometimes in the context of editing. When editing a record, the lookup component is removed (using an if server-side, so the template is no longer loaded at all) and when that happens I get this error.
$refs.lookupResult._data.result.twitter": TypeError: Cannot read property '_data' of undefined
This makes sense. lookupResult is defined when I include the template, and when editing I am removing this line:
<address-lookup v-ref:lookup-result></address-lookup>
I've worked around it by including a version of each extra input without the v-model attribute, again using a server-side if. But there are quite a few of these and it's getting a bit messy.
Is there a cleaner approach I could be using to better achieve this?
So I don't know the hierarchy of your layout, it isn't indicated above, but assuming that address-lookup component is a child of your parent, and you in fact need the results of address lookup in that parent, eg:
<parent-component> <!-- where you need the data -->
<address-lookup></address-lookup> <!-- where you lookup the data -->
</parent-component>
then you can simply pass the data props, either top-down only (default) or bidirectionally by defining 'address' for example on your parent's vue data hook:
// parent's data() function
data = function () {
return {
address: {}
}
}
// parent template, passed address with .sync modifier (to make it bi-directional)
<parent-component>
<address-lookup :address.sync='address'></address-lookup>
</parent-component>
// have the props accepted in the address look up component
var addressComponent = Vue.extend({
props: ['address']
})
Now in your $.ajax success function, simply set the props you need on this.address. Of course you can do this with all the props you need: errors, results, state etc. Even better, if you can nest them into a single key on the parent, you can pass the single key for the object containing all four elements instead of all four separately.