Farzher
Farzher

Reputation: 14563

vuejs 2 v-for :key not working, html being replaced?

I'm rendering some HTML in a v-for

But everytime I change any of the data, all my html gets replaced (input fields lose their values)

I tried giving the :key all kinds of different values

I didn't have this problem in vue v1, only in v2

http://jsbin.com/jomuzexihu/1/edit?html,js,output

Upvotes: 2

Views: 4674

Answers (3)

zhaorui
zhaorui

Reputation: 27

I guess, for performance optimization, when the key is not change, Vue will not rerender the dom, but will update the data import through directive.So when your input element is import through an directive (v-html), it will be rerendered everytime when stuff changes.

Due to the vue is not a string template engines, but template based on dom, so in the case of @craig_h 's example , to use the incomming html in a string template within a component:

Vue.component('unknown-html', {
   props: {
     html: ""
   },
   template: '<div><div v-html="html"></div>'
})  

view:
<unknown-html :html="thing.html"></unknown-html>

So when the stuff changes, it will not to rerender the template declare in string, for vue is not a string template engine.

Upvotes: 0

craig_h
craig_h

Reputation: 32704

I had a little play with this and it appears that Vue does not re-render the entire list when using <input /> or if you use a component but it does with v-html. Heres the fiddle for the comparison:

https://jsfiddle.net/cxataxcf/

The key actually isn't needed here because the list isn't being re-ordered, so your issue isn't to do with :key but rather with v-html. Heres what the docs say about v-html:

The contents are inserted as plain HTML - data bindings are ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.

So I guess this is where the problem lies.

It might be worth raising an issue on Vue's github page to see whether this is the expected behavior for v-html, but Vue 2.0 is much more heavily focused on components than vue 1.x and doesn't appear to recommend using v-html, so it may just be that you need to re-factor your code to use components instead.

Edit

The solution to this problem is to simply wrap the code in a component and pass the HTML as a prop:

Vue.component('unknown-html', {
  props: {
    html: ""
  },
  template: '<div><div v-html="html"></div>'
})

The markup:

  <unknown-html :html="thing.html"></unknown-html>

And the View model:

var app = new Vue({
  el: '#app',
  data: {
    numInputs: 1,
    stuff: [{
      'html':'<input />'
    }, {
      'html':'<button>Foo</button>'
    }]
  }
})

Here's the JSFiddle: https://jsfiddle.net/wrox5acb/

Upvotes: 5

Mani Jagadeesan
Mani Jagadeesan

Reputation: 24265

You are trying to inject raw html directly into the DOM. Probably it was possible in earlier versions of Vue.js, but it is definitely not the recommended way.

You can instead have an array of objects and bind it to html as shown in this jsFiddle: https://jsfiddle.net/43xz6xqz/

Vue.js version: 2.0.3

In the example above, vue.js is responsible for creating the input elements and also for binding these input elements to the object values using v-model.

To extract these values, you may use a computed property as shown in the sample code.

Upvotes: 1

Related Questions