vuejs / Discussion

Vue.js discussion
167 stars 17 forks source link

Accessing Vue HTML Elements through vm.$$ and v-el #310

Open maedi opened 9 years ago

maedi commented 9 years ago

I'd like to create an input field that responds to a keyboard enter by adding a new field below and focusing the cursor on that field. However v-el doesn't appear to work on sub HTML elements, just the element that corresponds to the Vue.

HTML

<ul id="fields" v-el="thisWorks">
  <li v-repeat="fields">
    <input v-model="text" v-el="field{{$index}}" v-on="keyup:newField(this) | key 'enter'"></input>
  </li>
</ul>

JS


var field = function() {
  this.text = '';
}
var fields = new Vue({
  el: "#fields",
  data: {
    fields: [new field()]
  },
  methods: {
    newField: function (component) {
      // focus on new field
      var self = component;
      Vue.nextTick(function () {
        // DOESN'T WORK
        //var newFieldName = "field" + (self.$index + 1);
        //this.$$[newFieldName].focus();
      });
      // add new field
      this.$data.fields.push(new field());
    }
  }
})

Error

Uncaught TypeError: Cannot read property 'field1' of undefined even though the object is there in fields.$data.fields and in the DOM.

fields.$$.thisWorks is accessible.

Happy to hear a more Vue way of doing this using components etc.

simplesmiler commented 9 years ago

v-el is a "literal directive".

Literal directives treat their attribute value as a plain string; ... Literal directives accept mustache expressions inside their value, but these expressions will be evaluated only once on first compile and do not react to data changes.

Generally speaking, DOM operations belong to directives, so I would write a custom directive, that focuses item on bind: https://jsfiddle.net/simplesmiler/48jxvnzt/

swift1 commented 9 years ago

Very nice solution, but | key enter doesn't work. Replace it with | key 'enter' and everything works great. :)

maedi commented 9 years ago

@simplesmiler Thank you! I'll wrap my head around the code.

I'd also like to move the focus up and down fields with the keyboard arrow keys. Is directives also the place for this kind of logic? I keep thinking of jQuery... but I know that will probably lead to spaghetti code.

swift1 commented 9 years ago

Ye, jquery will of course lead to spaghetti code. :smile: I've extended @simplesmiler's example to give you a possible solution: https://jsfiddle.net/48jxvnzt/2/

If you don't want to use any global functions or global directives, you can do it like this: https://jsfiddle.net/48jxvnzt/3/

simplesmiler commented 9 years ago

@swift1 you are correct with the | key 'enter', my cdn was pointing at 0.11.8 instead of the latest.

@maedi I would probably make focus a part of the viewmodel, listen to the focus event of inputs, and introduce methods focusUp and focusDown.

Something like this: https://jsfiddle.net/simplesmiler/48jxvnzt/7/ Note the directive now takes a boolean value.

appsparkler commented 7 years ago

i guess now it is ref and this.$refs

...
<h1 ref="heading">Hello World!</h1>
...
// Vue Instance
...
someMethod: function( ) {
  this.$refs.heading;    // this is the hook for the <h1> element above...
}
...