Reputation: 344
I'm trying to build a simple listing system that shows a list of items for different platforms, each platform is on a seperate tab . I created the tab switching logic via VueJS from scratch .
What I'm doing:
Basically I have two platforms : twitter and facebook, when user click on one of the tabs, the frontend send an ajax request to my server to fetch posts for that platform and render them via v-for .
I added a button called edit for each post, when user press it , it calls a function edit(p), where p is the current post that user want to edit .
in edit(p) I change an atrribute p.editing which using v-if shows a text area and a timepicker (I'm using flatpicker) for that post .
What's Wrong:
All this works fine when I'm on the first tab, but once I switch the tab, it stop working, after debugging I noticed that v-if is not working event p.editing is updated when edit(p) is called, here's the code :
var posts_app = new Vue({
el: "#posts_app",
data: {
platforms : ['facebook','twitter'],
current_tab: {
'facebook' : true,
'twitter': false
},
platform_posts: {
'facebook': [],
'twitter': []
},
posts: undefined,
},
methods:{
showTab: function(i){
platform = this.platforms[i]
// UI stuff : to make the clicked tab active
for(p in this.current_tab){
if(p == platform){
this.current_tab[p] = true
}
else{
this.current_tab[p] = false
}
}
// Show content by platform
this.posts = this.platform_posts[platform]
},
edit: function(p){
p.editing = true
console.log(p)
Vue.nextTick(function(){
document.getElementsByClassName("dt-input")[0].flatpickr({enableTime : true});
})
},
save: function(p){
p.editing = false
}
},
created(){
self = this
posts_loaded = false
for(var i = 0;i < this.platforms.length; i++){
(function(index){
self.$http.get('/fan/posts',{params:{platform : self.platforms[index]}}).then(function(resp){
self.platform_posts[self.platforms[index]] = resp.body
posts_loaded = true
})//Promise of Ajax call
}// Closure body
)(i)//Closure
}
this.showTab(0)
},
delimiters: ['[[',']]']
})
and my basic html template :
<div class = "panel-body">
<img class = "pull-right responsive" v-bind:src = "p.image"/>
<textarea v-if = "p.editing" class = "post-text-input" v-model = "p.text"></textarea>
<p class = "post-text" v-if = "!p.editing">[[p.text]]</p>
<p class = "post-source" v-if = "p.type == 'article'"> Source : [[post_source(p)]]</p>
<p class = "post-time"><b>Scheduled on <i v-if = "!p.editing">[[p.time]] </i></b>
<input placeholder="Choose a date and a time" class = "flatpickr dt-input" v-model = "p.time" v-if = "p.editing" />
</p>
</div>
<div class = "panel-footer clearfix">
<button class = "btn btn-danger">Delete</button>
<button class = "btn btn-info pull-right" @click = "edit(p)" v-if = "!p.editing">Edit</button>
<button class = "btn btn-success pull-right" @click = "save(p)" v-if = "p.editing">Save</button>
</div>
Code explanation:
So, when a tab is clicked, showTab(index) is called where index is the number of tab, if index is 0 then we switched to facebook tab, if it's 1 then we're in the twitter tab, we send an AJAX request to get the posts for that current platform (tab) and fill it in platform_posts[current_platform], we then render them via v-for . All of this is working like a charm .
Second part, when user click on the edit button for a given post, it replace the text paragraph element with a textarea using v-model to keep track of change and update the time paragraph with an input which acts as datetime picker via flatpickr library . Basically this lib can turn any input into a datetime pickr using this line of code :
elemnt.flatpickr({config_options})
Where element is an HTML element . You can notice that I'm using Vue.nextTick, this is to make sure that the input is not hidden anymore (it shouldn't be since p.editing is updated) . All of this work like a charm when I'm on the first tab, the problem is that when I switch the tab it stop working .
Here's a gif I made to show you the error : http://imgur.com/a/QME4P
As you can see, the behaviour is very weird, it works perfectly on the twitter tab and it's weird on the facebook tab .
Upvotes: 2
Views: 648
Reputation: 2529
It looks like you're breaking reactivity somewhere. Read about Reactivity. In short, you cannot mutate an array or add a new property to an already created object.
For example, instead of p.editing = true you can do:
this.$set(p, 'editing', true)
Another key concept is to replace an array instead of mutating an array.
I would recommend moving your get posts out of created() and into a method called by created(), as you may want to reuse it to pull posts again. Also you should set posts to an empty array instead of undefined.
Upvotes: 1