Trying to change data inside #click inside v-for - javascript

i have a v-for loop as my selection for dialog boxes I want to open
<v-card #click="page.model = true">
page.model is my v-model for a v-dialog
data() {
return {
dialog1: false,
dialog2: false,
pages: [
{
id: "1",
model: "dialog1",
},
{
id: "2",
model: "dialog2",
},
],
};
},
howcome #click="page.model = true" doesn't work but #click=dialog1 = true " does?
I also tried :#click="page.model = true" and #click="${page.model} = true"
Thank you in advance

So we dont see your modal HTML so I presume something like this:
<v-card v-for="page in pages" #click="changePage(page.id)">
<modal v-model="pages[0].isOpen">[CONTAIN OF PAGE 1]</modal>
<modal v-model="pages[1].isOpen">[CONTAIN OF PAGE 2]</modal>
data() {
return {
pages: [
{
id: "1",
model: "dialog1",
isOpen: false,
},
{
id: "2",
model: "dialog2",
isOpen: false,
},
],
},
methods: {
changePage(id) {
// close all other modal page
this.pages.each(el => el.isOpen = false);
// open the good one
const index = this.pages.findIndex(el => el.id == id);
this.pages[index].isOpen = true;
}
},

I have done something similar. Call a method and pass index of item. In the method you can then access the specific model via index
<v-card #click="updateDialog(index)">
updateDialog(i): {
this.pages[i].model = true
}

Related

V-if directive not dynamically updating on variable change

I'm trying to create a button in my program that toggles on a number of other things and removes itself once it's clicked. The relevant HTML is as follows:
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<list v-for="name in chosenNames" v-bind:name="name"></list>
</ul>
</div>
In this, the unordered list should be shown once the variable "showlists" is true and the button should be removed once "showlists" is true. My Vue app looks like this:
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
showlists = true;
}
}
})
Based on this, the "showlists" variable starts as false, and the program works as intended with the button showing and the list hidden. Once the button is clicked, the function runs and showlists is then set to true (I confirmed this in my troubleshooting efforts). However, once this occurs, the DOM does not dynamically update and instead just remains as it was at the start.
Sorry if this is something really basic, I'm very new to Vue and still trying to learn :)
Any and all help would be appreciated.
You have to use the "this" keyword in your "revel" method before showlists like this.showlists = true; variable in your "Vue" instance.
For example, you can write like as follows
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<list v-for="(name, index) in chosenNames" :name="name" :key="'list-'+index"></list>
</ul>
</div>
And for new "Vue" instance
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
this.showlists = true;
}
}
})
I hope that might solve the problem :)
your code has 4 bug:
v-bind is set element's attribute, not innerHTML
showlists need change to this.showlists
showlists = true; is always set to true
list isn't valid html tag, you need li
below is right code:
<div id="app">
<button #click="reveal" v-if="!showlists">Start</button>
<ul v-if="showlists">
<li v-for="name in chosenNames" v-html="name"></li>
</ul>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
showlists: false,
chosenNames: [
{ text: "name1" },
{ text: "name2" },
{ text: "name3" },
]
},
methods: {
reveal: function() {
this.showlists = !this.showlists;
}
}
})
</script>

How to emit an event when the user clicks on a specific page number?

export default {
props: {
pageNumber: {
type: Number,
required: true
}
},
data() {
return {
currentPage: 1,
perPage: 12,
},
computed: {
rows() {
return this.productsList.length;
},
paginatedItems() {
return this.productsList.slice(
this.currentPage * this.perPage,
(this.currentPage + 1) * this.perPage
);
},
methods: {
handleClick(event, pageNumber) {
alert('hi');
},
},
<div class="listview-plp" v-for="product in paginatedItems" :key="product.key" id="product" :items="productsList" :per-page="perPage" :current-page="currentPage">
<div>ds</div>
<b-pagination v-model="currentPage" :total-rows="rows" :per-page="perPage" #change="loadPage" :pageNumber="currentPage" #page-click="handleClick(event, pageNumber)"></b-pagination>
I want to emit an event when the user clicks on a specific page number? For that #page-click="handleClick(event, pageNumber)" i have taken an event in the method. But using page number is not pointing to specific page, So i have tool some prop value and then passing it to them,
But not sure how to pass value for each page.
You don't need to specify the parameters in the template,
#page-click="handleClick"
the method :
methods: {
handleClick(event ,pageNumber) {
alert('hi ', pageNumber);
},
},

How to disable Vue Component if Ajax call will fail

I'm working on a Vue project which has a component for loading content into a modal via an ajax call:
<load-content target="foo"></load-content>
<load-content target="bar"></load-content>
<load-content target="oof"></load-content>
<load-content target="rab"></load-content>
Here's an example template:
<template>
<span class="load-content-wrapper" v-on:click="load">
Click
</span>
</template>
<script>
export default {
name: 'load content',
props: {
target: {
type: String,
required: true
}
},
methods: {
load() {
$('#load-content-modal').modal('show');
this.$store.dispatch('loadContent', this.target);
},
}
};
</script>
Which would trigger this example action:
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
});
},
};
This all works well, except we cannot guarantee that the Ajax call will always return content. Depending on the target it could return 404.
Ideally I want to automatically disable individual load-content components if '/api/fetch-content/' + target isn't available to prevent users from trying to select unavailable content.
What is the correct/ most efficient way to do this?
You should make your "target" field not required and instead add a default value empty string.
And add an "if" condition to your load method. If "target" is empty, it will not proceed.
export default {
name: 'load content',
props: {
target: {
type: String,
default: ''
}
},
methods: {
load() {
if (!this.target) return;
$('#load-content-modal').modal('show');
this.$store.dispatch('loadContent', this.target);
},
}
};
Create a store variable loading and mutate it in your actions as follows:
loading: false
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
commit(setLoading)
});
},
};
Then in muatations ->
setLoading (state, loading) {
state.loading = true
}
Now in your vue file use this store variable and check if it is true then load the component.You may check this created or mounted events of the component.
Option 1
Preemptively load the content, and disable the ones that return an error.
This is what the parent component will look like
<template>
<load-content
v-for="(target, index) in loadedTargets"
:key="index"
target="target"
/>
</template>
<script>
export default {
name: 'load content parent',
data: function() {
return {
targets: [
{link: 'foo', data: null, loaded: false, error: null},
{link: 'bar', data: null, loaded: false, error: null},
{link: 'oof', data: null, loaded: false, error: null},
{link: 'rab', data: null, loaded: false, error: null},
]
}
},
computed: {
loadedTargets() {
return this.targets.filter(t => t.loaded)
}
},
methods: {
load(target) {
const self = this;
$.ajax({
url: '/api/fetch-content/' + target.link,
}).then((data) => {
self.targets[indexOf(target)].data = data
self.targets[indexOf(target)].loaded = true
}).catch((error) => {
self.targets[indexOf(target)].error = error
});
},
},
mounted() {
this.targets.forEach(target => this.load(target))
}
};
</script>
Option 2
Preemptive loading is expensive (and since I don't know how many targets you might have), you could also show success/error in the modal. Proper UX would dictate that an explicit action by the user should lead to a result (i.e. if the user clicks a link, he should either see data in the modal, or an error)
This is what your action will look like:
const actions = {
loadContent ({ commit }, target) {
$.ajax({
url: '/api/fetch-content/' + target,
}).then((data) => {
// Load Modal Window
}).catch((error) => {
// Load Modal Window, and show the error
});
},
};

mergeOptions changes not reflected

I'm trying to get a badge to display on one of the navigation tabs.
onClickSetBadge() {
console.log('Button pressed!')
Navigation.mergeOptions(this.props.componentId, {
bottomTab: {
badge: `TeSt`
}
});
}
I'm calling it inside the view I'm rendering.
<ButtonView text='SUP' onPress={() => {this.onClickSetBadge()}} />
The log statement shows up in my console, however, the badge is not shown.
According to the official document: https://wix.github.io/react-native-navigation/#/docs/layout-types?id=updating-options-for-a-specific-tab , that is how it works:
1) Define an id for the specific tab:
stack: {
id: 'CartTab',
children: [{
component: {
name: 'store-cart',
}
}],
options: {
bottomTab: {
text: 'Cart',
icon: require('../asset/image/menu/cart.png'),
}
}
}
2) Use the tab id to update when needed:
Navigation.mergeOptions('CartTab', {
bottomTab: {
badge: cart.length > 0 ? cart.length.toString() : ''
}
});

Sending data to a non parent component in VueJs

I am trying to replicate the TODO MVC in VueJs.
(Please checkout this codepen : http://codepen.io/sankalpsingha/pen/gwymJg )
I have created a component called 'todo-list' with the following code :
Vue.component('todo-list',{
template: '#todo-list',
props: ['todo'],
data: function() {
return {
// Let us set up a isEditing Boolean so that we can know if the user
// will edit something and we need to change the state to reflect it.
isEditing: false,
}
},
methods: {
enableEditing: function() {
this.isEditing = true;
},
editTodo: function(todo) {
// todo.todo = todo.todo.trim();
this.isEditing = false;
},
removeTodo: function(todo) {
//this.todos.$remove(todo); // --> This part is not working?
}
}
});
However, I have the data defined in the app instance :
var app = new Vue({
el: '#todo-section',
data: {
newTodo: '',
todos: [
{
id: 1,
todo: 'Go to the grocery',
completed: false,
},
{
id: 2,
todo: 'See the movie',
completed: true,
},
{
id: 3,
todo: 'Jack Reacher : Tom Cruise',
completed: false,
}
]
},
methods: {
addTodo: function() {
// This will not allow any empty items to be added.
if(this.newTodo.trim() == '') {
return;
}
this.todos.push({
todo: this.newTodo.trim(),
completed: false,
});
this.newTodo = '';
}
}
});
I am not able to delete a single Todo from the list. My guess is that I have to send a emit message to the app instance and put up a listener there to delete the data from it? How do I delete the data?
When I tried to delete by clicking the x button in your codePen example, I see the error: this.$parent.todos.$remove is not a function.
I have not looked deeply into your code. But attempting to access parent component methods using this.$parent is not a good idea. Reason: a component can be used anywhere, and assuming that it will have a $parent with a particular property or method is risky.
As you suggested in your question, you need to use $emit from the child component to delete the data.
There was another similar question here few days ago, for which I created a jsFiddle: https://jsfiddle.net/mani04/4kyzkgLu/
The child component has some code like:
<button #click="$emit('delete-row')">Delete</button>
This sends out an event to parent component. Parent component can subscribe to that event using v-on as seen in that jsFiddle example.
Here is that other question for reference: Delete a Vue child component
It's preferable to use your methods (DeleteTodo, EditTodo...) in your parent.
var app = new Vue({
el: '#app',
data: {
newTodo: '',
todos: [{
id: 1,
title: 'Go to the grocery',
completed: false
}, {
id: 2,
title: 'See the movie',
completed: true
}, {
id: 3,
title: 'Jack Reacher : Tom Cruise',
completed: false
}]
},
methods: {
addTodo: function() {
this.todos.push({
todo: this.newTodo.trim(),
completed: false
});
this.newTodo = ''
},
deleteTodo: function(todo) {
this.todos = this.todos.filter(function(i) {
return i !== todo
})
}
}
});
<div id="app">
<ul>
<li v-for="todo in todos">{{ todo.title }}
<button #click.prevent="deleteTodo(todo)">
Delete
</button>
</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>

Categories