From the component I want to access methods of the parent.
(Without props)
Here's the HTML:
<div id="el">
<user v-for="user in users" :item="user"></user>
</div>
Here's the Vue code:
var usersData = [
{ id:1, firstname:'John', lastname: 'Doe' },
{ id:2, firstname:'Martin', lastname: 'Bust' }
];
var vm = new Vue({
el: '#el',
data: { users: usersData },
methods: {
getFullName: function (user) {
return user.id + '. ' + user.firstname + ' ' + user.lastname;
}
},
components: {
user: {
template: '<span>{{ fullName }}</span>',
props: ['item'],
computed: {
fullName: function(){
return this.$parent.getFullName(this.item);
}
},
}
}
});
VueJS version: 2.0.2
Both are this.$parent.$options.methods.getFullName() and this.$parent.methods.getFullName() not working.
For Vue.js version 2.2.0+ you can use dependency injection with inject and provide like this:
HTML:
<div id="el">
<user v-for="user in users" :item="user"></user>
</div>
JavaScript:
var usersData = [
{ id:1, firstname:'John', lastname: 'Doe' },
{ id:2, firstname:'Martin', lastname: 'Bust' }
];
var vm = new Vue({
el: '#el',
data: { users: usersData },
methods: {
getFullName: function (user) {
return user.id + '. ' + user.firstname + ' ' + user.lastname;
}
},
provide: function () {
return {
getFullName: this.getFullName
}
},
components: {
user: {
template: '<span>{{ fullName }}</span>',
inject: ['getFullName'],
props: ['item'],
computed: {
fullName: function(){
return this.getFullName(this.item);
}
},
}
}
});
Fiddle: https://jsfiddle.net/haaiee/v1ahoytm/2/
Related
I need to fetch latest data when mount vue component, but need to check the props first. but it allways getting undefined.
it looks like this code
Vue.component('book', {
props: ["showLatest"],
data: function() {
return {
books: null
}
},
template: '<ul><li v-for="book in books">This is a book {{ book.name }} <small><i>{{ book.publisher}}</i></small></li></ul>',
method: {
fetch: function() {
this.books = [
{
name: "Latest 1",
publisher: "publisher_test1"
},
{
name: "Latest 2",
publisher: "publisher_test2"
},
{
name: "Latest 3",
publisher: "publisher_test3"
}
];
}
},
mounted: function() {
console.log(this.showLatest);
if(!this.showLatest) {
this.books = [
{
name: "Test 1",
publisher: "publisher_test1"
},
{
name: "Test 2",
publisher: "publisher_test2"
},
{
name: "Test 3",
publisher: "publisher_test3"
}
];
} else {
this.fetch();
}
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Digital Library!'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ message }}
<book :showLatest="true"></book>
</div>
Why showLatest always getting undefined. if this is not good approach, how to make it work..?
Hopefully anyone can help
Thanks in advance
The prop should be written in kebab-case format when it's used in parent like <book :show-latest="true"></book> or just <book show-latest></book> and in the child component fix method to methods :
Vue.component('book', {
props: ["showLatest"],
data: function() {
return {
books: null
}
},
template: '<ul><li v-for="book in books">This is a book {{ book.name }} <small><i>{{ book.publisher}}</i></small></li></ul>',
methods: {
fetch: function() {
this.books = [
{
name: "Latest 1",
publisher: "publisher_test1"
},
{
name: "Latest 2",
publisher: "publisher_test2"
},
{
name: "Latest 3",
publisher: "publisher_test3"
}
];
}
},
mounted: function() {
console.log(this.showLatest);
if(!this.showLatest) {
this.books = [
{
name: "Test 1",
publisher: "publisher_test1"
},
{
name: "Test 2",
publisher: "publisher_test2"
},
{
name: "Test 3",
publisher: "publisher_test3"
}
];
} else {
this.fetch();
}
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Digital Library!'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ message }}
<book :show-latest="true"></book>
</div>
I have this fiddle:
https://jsfiddle.net/pnqzspoe/12014/
I want to modify it a bit and want to display each node as a text area containing the corresponding text. Further, I want to give an option to 'reply' to it. This would mean insertion of a new text area into which we can enter text.
Here is the code:
<script type="text/x-template" id="item-template">
<li>
<div
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="(model, index) in model.children"
:key="index"
:model="model">
</item>
<li class="add" #click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
var data = {
name: 'My Tree',
children: [
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
}
]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object
},
data: function () {
return {
open: false
}
},
computed: {
isFolder: function () {
return this.model.children &&
this.model.children.length
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function () {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function () {
this.model.children.push({
name: 'new stuff'
})
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: {
treeData: data
}
})
What would be the template for this use-case?
If I don't understand your question wrongly...
Replace
{{model.name}}
with
<textarea v-model="model.name"></textarea>
should work?
I have an array of objects inside my Vue instance, and for each item I'd like to write a Computed property.
Each object has only two properties: firstName and lastName. I would like to write a Computed property for each named 'fullName', which is just a concatenation of firstName and lastName.
I'm familiar with implementing Computed properties of data object properties of a Vue instances, but when it comes to doing so with elements of an array, I get confused.
Currently, my code is this:
var app = new Vue({
el: '#app',
data: {
names: [{
firstName: 'Mike',
lastName: 'McDonald',
done: false
},
{
firstName: 'Alex',
lastName: 'Nemeth',
done: false
},
{
firstName: 'Nate',
lastName: 'Kostansek',
done: true
},
{
firstName: 'Ivan',
lastName: 'Wyrsta',
done: true
}
]
},
computed: {
fullName: function(name) {
return name.lastName + ', ' + name.firstName;
}
}
methods: {
toggle: function(name) {
name.done = !name.done;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id='app'>
<ol>
<li v-for='name in names'>
<input type='checkbox' v-bind:checked='name.done' v-on:change='toggle(name)' />
<span v-if='!name.done'>{{ fullName(name) }}</span>
<del v-else>{{ fullName(name) }}</del>
</li>
</ol>
</div>
And here is the respective jsFiddle
It's recommended to return a function with name as argument from the computed property :
var app = new Vue({
el: '#app',
data: {
names: [{
firstName: 'Mike',
lastName: 'McDonald',
done: false
},
{
firstName: 'Alex',
lastName: 'Nemeth',
done: false
},
{
firstName: 'Nate',
lastName: 'Kostansek',
done: true
},
{
firstName: 'Ivan',
lastName: 'Wyrsta',
done: true
}
]
},
computed: {
fullName(){
return (name)=>name.lastName + ', ' + name.firstName;
},
toggle() {
return (name)=>name.done = !name.done;
}
},
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id='app'>
<ol>
<li v-for='name in names'>
<input type='checkbox' v-bind:checked='name.done' v-on:change='toggle(name)' />
<span v-if='!name.done'>{{ fullName(name) }}</span>
<del v-else>{{ fullName(name) }}</del>
</li>
</ol>
</div>
Another solution is to loop through names array inside a computed property by concatenating firstname and lastname, after that return this array and loop through it in your template
var app = new Vue({
el: '#app',
data: {
names: [{
firstName: 'Mike',
lastName: 'McDonald',
done: false
},
{
firstName: 'Alex',
lastName: 'Nemeth',
done: false
},
{
firstName: 'Nate',
lastName: 'Kostansek',
done: true
},
{
firstName: 'Ivan',
lastName: 'Wyrsta',
done: true
}
]
},
computed: {
fullNames() {
return this.names.map(name => {
let fl = {};
fl.fname = name.firstName + ", " + name.lastName;
fl.done = name.done;
return fl;
})
}
},
methods: {
fullName: function(name) {
return name.lastName + ', ' + name.firstName;
},
toggle: function(name) {
name.done = !name.done;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id='app'>
<ol>
<li v-for='name in fullNames'>
<input type='checkbox' v-bind:checked='name.done' v-on:change='toggle(name)' />
<span v-if='!name.done'>{{ name.fname }}</span>
<del v-else>{{ name.fname }}</del>
</li>
</ol>
</div>
You can't use the 'computed' with a parameter.
Most probably you want to use a method:
example
<span>{{ fullName('Hi') }}</span>
methods: {
fullName(param) {
return `${this.param} ${this.firstName} ${this.lastName}`
}
}
If I have code like the code below in my vue.js, upon clicking a button, how can I only display the array item I clicked ( for e.g, Donnie) and hide all of the rest? (Joanne, Peter e.t.c), then when you click the only displayed element again, make all of the other array elements display again?
const app = new Vue({
el: '#app',
data: {
keyword: '',
friends: [
{
name: "Donnie",
age: "20"
},
{
name: "Joanne",
age:"19",
},
{
name: "David",
age: "26"
},
{
name: "Peter",
age: "23"
},
{
name: "John",
age: "29"
},
{
name: "Jason",
age: "19"
},
],
},
computed: {
filteredList() {
return this.friends.filter((friend) => {
return friend.name.toLowerCase().includes(this.keyword) + friend.age.includes(this.keyword) + friend.name.includes(this.keyword);
});
}
},
methods:{
exclude(friend) {
console.log(!friend.name);
},
}
})
HTML
<div v-for="friend in filteredList" class="card" #click="exclude(friend)">
{{friend.name}} - {{friend.age}}
</div>
You should be able to add an identity check to your filter expression if an item has been clicked.
Start by adding a property to store the clicked friend. I'll call mine selected
data {
selected: null,
keyword: '',
//etc
}
Then in your exclude method
exclude (friend) {
this.selected = this.selected ? null : friend
}
now your computed property can filter the list based on the selected friend first, then fall back to the keyword match
filteredList () {
return this.selected ? [this.selected] : this.friends.filter(friend => {
let search = this.keyword.trim().toLowerCase()
return friend.name.toLowerCase().includes(search) || friend.age.includes(search)
})
}
I think that's what you're looking for:
const app = new Vue({
el: '#app',
data: {
keyword: '',
friends: [
{
name: "Donnie",
age: "20"
},
{
name: "Joanne",
age:"19",
},
{
name: "David",
age: "26"
},
{
name: "Peter",
age: "23"
},
{
name: "John",
age: "29"
},
{
name: "Jason",
age: "19"
},
],
selected: null
},
computed: {
filteredList() {
if (!this.selected) {
return this.friends.filter((friend) => {
return friend.name.toLowerCase().includes(this.keyword) + friend.age.includes(this.keyword) + friend.name.includes(this.keyword);
});
} else {
return [this.selected];
}
},
},
methods:{
exclude(friend) {
if(!this.selected) {
this.selected = friend;
} else {
this.selected = null;
}
},
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<div v-for="friend in filteredList" class="card" #click="exclude(friend)">
{{friend.name}} - {{friend.age}}
</div>
</div>
The trick here is that the selected data property store the friend and also doubles as a checker if there's a friend, so if not, show all, if is, show only that one.
I'd like to import a helper class rather than inlining the logic inside my component. I get the following error:
http://eslint.org/docs/rules/no-unused-vars 'NavbarService' is defined but never used
/services/NavbarService.js
class NavbarService {
constructor (init) {
this.init = init;
}
static applications () {
return [
{ name: 'Administration' },
{ name: 'Standard' }
];
}
static views () {
return [
{ name: 'Providers', path: '/providers' },
{ name: 'Authorities', path: '/authorities' },
{ name: 'Services', path: '/services' },
{ name: 'Codes', path: '/codes' }
];
}
}
/components/Navbar.vue
import NavbarService from '../services/NavbarService.js';
export default {
data () {
return {
versionIsVisible: false,
version: '2.0.0',
applications: NavbarService.applications(),
views: NavbarService.views()
};
},
methods: {
showApplications: function () {
this.applications = NavbarService.applications();
this.views = [];
return;
}
}
};
Following Roy J's suggestion, I changed /services/NavbarService.js to:
export default {
applications: function () {
return [
{ name: 'Administration' },
{ name: 'Standard' }
];
},
views: function () {
return [
{ name: 'Providers', path: '/providers' },
{ name: 'Authorities', path: '/authorities' },
{ name: 'Services', path: '/services' },
{ name: 'Codes', path: '/codes' }
];
}
};