2017-02-26 38 views
0

によってトリガしたイベントをキャッチした後にレンダリングされません。子コンポーネント(先読みコンポーネント)からカスタムイベントを送出していますが、v-onディレクティブを使用してこのイベントをキャッチしています。次の文で:(「選択先行入力」)先行入力選択が行われた後、私はカスタムイベントを発する上記のコードでVuejs 2のV-場合ディレクティブは、私はvuejs 2.0とlaravel 5.3を使用している子コンポーネント

<template> 
 
    <input ref="input" class="typeahead-suggestions" 
 
      :class="classes" 
 
      :id = "id" 
 
      v-bind:value="value" 
 
      v-on:input="updateValue($event.target.value)" 
 
      v-on:blur="formatValue" 
 
      :placeholder="placeholder"> 
 
</template> 
 
<script> 
 
    var Bloodhound = require('typeahead.js') 
 
    export default { 
 
     data: function() { 
 
      var id = 'typeahead-suggestion' + parseInt(Math.random() *100000); 
 
      return { 
 
       id, 
 
       defaultSuggestions: [], 
 
       query: '' 
 
      }; 
 
     }, 
 
     props: { 
 
      param: { 
 
       type: String, 
 
       default: 'item' 
 
      }, 
 
      value: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      classes: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      displayKey: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      suggestionTemplate: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      name: { 
 
       type: String, 
 
       default: 'Vue Auto Complete' 
 
      }, 
 
      prefetch: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      defaultSuggestion: { 
 
       type: Boolean, 
 
       default: false 
 
      }, 
 
      remote: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      placeholder: { 
 
       type: String, 
 
       default: '' 
 
      }, 
 
      local: { 
 
       type: Array, 
 
       default: function() { 
 
        return []; 
 
       } 
 
      }, 
 
      responseWrapper: { 
 
       type: String, 
 
       default: '' 
 
      } 
 
     }, 
 
     watch: { 
 
      local: function(newVal) { 
 
       if (this.defaultSuggestion) { 
 
        this.defaultSuggestions = [...newVal]; 
 
       } 
 
       this.resetTypeahead(); 
 
      } 
 
     }, 
 
     mounted: function() { 
 
      this.initTypeahead(); 
 
      if (this.local.length) { 
 
       this.defaultSuggestions = [...this.local]; 
 
      } 
 
     }, 
 
     methods: { 
 
      updateValue: function (value) { 
 
       this.$emit('input', value); 
 
      }, 
 
      formatValue: function() { 
 
       this.$refs.input.value = this.value; 
 
      }, 
 
      transformer: function (response) { 
 
       if (this.responseWrapper) { 
 
        response = response[this.responseWrapper]; 
 
       } 
 
       if (this.defaultSuggestion && this.local.length === 0) { 
 
        this.defaultSuggestions = response.splice(0, 5); 
 
       } 
 
       return response; 
 
      }, 
 
      bloodhoundOption: function() { 
 
       var bloodhoundConfig = {}; 
 
       if (this.prefetch) { 
 
        var prefetch = { 
 
         cache: false, 
 
         url: this.prefetch 
 
        }; 
 
        if (this.defaultSuggestion) { 
 
         prefetch = {...prefetch, transform: this.transformer}; 
 
        } 
 
        bloodhoundConfig = { prefetch}; 
 
       } 
 
       if (this.local) { 
 
        bloodhoundConfig = { 
 
         local: this.local, 
 
         ...bloodhoundConfig 
 
        } 
 
       } 
 
       if (this.remote) { 
 
        bloodhoundConfig = { 
 
         remote: { 
 
          url: this.remote, 
 
          wildcard: '%QUERY', 
 
          transform: this.transformer 
 
         }, 
 
         ...bloodhoundConfig 
 
        } 
 
       } 
 
       return bloodhoundConfig; 
 
      }, 
 
      parseTemplate: function(data) { 
 
       var res = Vue.compile(this.suggestionTemplate); 
 
       var vm = new Vue({ 
 
        data, 
 
        render: res.render, 
 
        staticRenderFns: res.staticRenderFns 
 
       }).$mount(); 
 
       return vm.$el; 
 
      }, 
 
      getSource: function() { 
 
       var self = this; 
 
       var bloodhoundConfig = this.bloodhoundOption(); 
 
       var datumTokenizer = this.displayKey ? Bloodhound.tokenizers.obj.whitespace(this.displayKey) 
 
                : Bloodhound.tokenizers.whitespace; 
 
       var engine = new Bloodhound({ 
 
        datumTokenizer, 
 
        queryTokenizer: Bloodhound.tokenizers.whitespace, 
 
        ...bloodhoundConfig 
 
       }); 
 
       var source = function(q, sync, async) { 
 
        if (q === '' && self.defaultSuggestions.length>0 && self.defaultSuggestion) { 
 
         sync(self.defaultSuggestions); 
 
        } else { 
 
         engine.search(q, sync, async); 
 
        } 
 
       }; 
 
       return this.defaultSuggestion ? source : engine; 
 
      }, 
 
      resetTypeahead: function() { 
 
       $(document).find('#' + this.id).typeahead('destroy'); 
 
       this.initTypeahead(); 
 
      }, 
 
      initTypeahead: function() { 
 
       var self = this; 
 
       var templates = {}; 
 
       if (this.suggestionTemplate) { 
 
        templates = {suggestion: self.parseTemplate} 
 
       }; 
 
       var dataset = { 
 
        name: 'Typeahead-Suggestion', 
 
        display: this.displayKey, 
 
        source: this.getSource(), 
 
        templates 
 
       }; 
 
       $(document).find('#' + self.id).typeahead({ 
 
        minLength: 0, 
 
        highlight: true 
 
       }, dataset) 
 
       .on('typeahead:select', function(event, suggession) { 
 
        self.$emit('input', self.displayKey? suggession[self.displayKey]: suggession); 
 
        self.$emit('selected', suggession); 
 

 
        // Set value of hidden input to the id of selected item 
 
        $('input[name="' + self.param + '"]').attr("value", suggession['id']); 
 

 
        self.$emit(self.param + '_typeahead'); 
 
       }); 
 
      } 
 
     } 
 
    } 
 
</script>

:ここ

は私のコンポーネントのコードです:ここでは

self.$emit(self.param + '_typeahead'); 

は私のルートVUEのインスタンスである:

var typeahead = require('./components/typeahead.vue'); 
 

 
if (formElm = document.getElementById('form')) { 
 

 
    new Vue({ 
 
     el: "#form", 
 
     data: { 
 
      form: new Form(formElm), 
 
      initialData: (typeof initialData !== 'undefined') ? initialData : [], 
 
      categories: (typeof categories !== 'undefined') ? categories : [], 
 
      parents: (typeof parents !== 'undefined') ? parents : [] 
 
     }, 
 
     components: { 
 
      'typeahead': typeahead 
 
     }, 
 
     mounted() { 
 
      if (typeof initialData !== 'undefined') { 
 
       for (let field in initialData) { 
 
        this.form[field] = initialData[field]; 
 
       } 
 
      } 
 
     }, 
 
     methods: { 
 
      onSubmit() { 
 

 
       // get all the fields 
 
       let formData = this.form.data(); 
 
       let form  = this.form; 
 
       let formInfo = form.info(formElm); 
 

 
       // setup the constraints for validate.js 
 
       var constraints = { 
 
        name: { 
 
         presence: { 
 
          message: "is required." 
 
         } 
 
        }, 
 
        description: { 
 
         presence: { 
 
          message: "is required." 
 
         } 
 
        }, 
 
        category_id: { 
 
         presence: { 
 
          message: "is required." 
 
         } 
 
        } 
 
       }; 
 

 
       // validate the fields 
 
       validate.async(formData, constraints) 
 
         .then(function(success) { 
 
          if (formInfo['method'] == 'PUT') { 
 
           form.put(formInfo['url']); 
 
          } else { 
 
           form.post(formInfo['url']); 
 
          } 
 
         }) 
 
         .catch(function(error) { 
 
          form.onFail(error); 
 
         }); 
 
      }, 
 

 
      onSuccess(response) { 
 
       form.reset(); 
 
      } 
 
     } 
 
    }); 
 
}

そして、次の私は、このコンポーネントを使用して、私のブレードのテンプレートです:私は、コンポーネントタグにイベントをキャッチする上でテンプレートで

  <form method="post" id="form" action="{{ url('admin/eventType') }}" @submit.prevent="onSubmit" 
 
        @keydown="form.errors.clear($event.target.name)"> 
 
       {{ csrf_field() }} 
 
       <div class="form-group"> 
 
        <label for="name">Name</label> 
 
        <input type="text" class="form-control" id="name" name="name" v-model="form.name" placeholder="Name"> 
 
        <span class="help text-danger" v-if="form.errors.has('name')" v-text="form.errors.get('name')"></span> 
 
       </div> 
 
       <div class="form-group"> 
 
        <label for="description">Description</label> 
 
        <textarea class="form-control" id="description" name="description" v-model="form.description" placeholder="Description"></textarea> 
 
        <span class="help text-danger" v-if="form.errors.has('description')" v-text="form.errors.get('description')"></span> 
 
       </div> 
 
       <div class="form-group"> 
 
        <label for="category_id">Category</label> 
 
        <input type="hidden" id="category_id" name="category_id" v-model="form.category_id" /> 
 
        <typeahead v-on:category_id_typeahead="form.errors.clear('category_id')" param="category_id" :default-suggestion="true" :local="categories" display-key="value" classes="form-control"> 
 
        </typeahead> 
 
        <span class="help text-danger" v-if="form.errors.has('category_id')" v-text="form.errors.get('category_id')"></span> 
 
       </div> 
 
       <div class="form-group"> 
 
        <label for="parent_id">Parent</label> 
 
        <input type="hidden" id="parent_id" name="parent_id" v-model="form.parent_id" /> 
 
        <typeahead param="parent_id" :default-suggestion="true" :local="parents" display-key="value" classes="form-control"> 
 
        </typeahead> 
 
       </div> 
 
       <button type="submit" class="btn btn-default" :disabled="form.errors.any()">Create New Event Type</button> 
 
      </form>

V-に関する指令:

<typeahead v-on:category_id_typeahead="form.errors.clear('category_id')" 
      param="category_id" :default-suggestion="true" 
      :local="categories" display-key="value" 
      classes="form-control"> 

問題:「category_id_typeahead」は、このフィールドにエラーがクリアされますトリガので

<span class="help text-danger" v-if="form.errors.has('category_id')" v-text="form.errors.get('category_id')"></span> 

:私はメソッドの出力に基づいて、エラーテキストを表示するに決定V-かのディレクティブを使用していますform.errors.has( 'category_id')メソッドの出力はfalseにする必要があります。エラーは削除する必要がありますが、削除する必要はありません。 console.logで印刷した内容によると、エラーオブジェクトにはイベントをトリガーした後にこのフィールドのエラーは含まれませんが、フォームに別の変更が加えられるまでテキストは削除されません。 v-ifがこのステップでレンダリングされないようです。

const formToJSON = elements => [].reduce.call(elements, (data, element) => { 
 
    if (!['submit'].includes(element.type) && !['_token'].includes(element.name)) { 
 
     data[element.name] = element.value; 
 
    } 
 
    return data; 
 
}, {}); 
 

 
const formInfo = elements => [].reduce.call(elements, (data, element) => { 
 
    if (['_method'].includes(element.name)) { 
 
     data['method'] = element.value; 
 
    } 
 
    if (typeof initialData !== 'undefined' && data['method'] == "PUT") { 
 
     data['id'] = initialData['id']; 
 
    } 
 
    return data; 
 
}, {}); 
 

 
// get entity 
 
const currentEntity = function() { 
 
    url   = window.location.href; 
 
    adminPosition = url.indexOf('admin/') + 6; 
 
    entity  = url.substring(adminPosition, url.indexOf('/', adminPosition)); 
 

 
    return entity; 
 
} 
 

 
class Errors { 
 
    constructor() { 
 
     this.errors = { }; 
 
    } 
 

 
    has(field) { 
 
     console.log('has error field : ', field, ' => ', this.errors.hasOwnProperty(field)); 
 

 
     return this.errors.hasOwnProperty(field); 
 
    } 
 

 
    any() { 
 
     return Object.keys(this.errors).length > 0; 
 
    } 
 

 
    get(field) { 
 
     if (this.errors[field]) { 
 
      return this.errors[field][0]; 
 
     } 
 
    } 
 

 
    record(errors) { 
 
     this.errors = errors; 
 
    } 
 

 
    clear(field) { 
 
     if (field) { 
 
      console.log('Before : clear error of ', field, ' error:', this.errors[field]); 
 
      delete this.errors[field]; 
 

 
      return; 
 
     } 
 

 
     this.errors = {}; 
 
    } 
 
} 
 

 
class Form { 
 
    constructor(formElm) { 
 
     // get form data 
 
     data = formToJSON(formElm.elements); 
 

 
     this.originalData = data; 
 

 
     for (let field in data) { 
 
      this[field] = data[field]; 
 
     } 
 

 
     this.errors = new Errors(); 
 
    } 
 

 
    info(formElm) { 
 
     data = formInfo(formElm.elements); 
 
     entity = currentEntity(); 
 
     if (data['method'] == 'PUT') { 
 
       data['url'] = '/admin' + '/' + entity + '/' + data['id']; 
 
     } else { 
 
       data['url'] = '/admin' + '/' + entity; 
 
     } 
 

 
     return data; 
 
    } 
 

 
    data() { 
 
     let data = {}; 
 
     for (let property in this.originalData) { 
 
      var propertyValue = document.getElementById(property); 
 
      if (typeof propertyValue !== 'undefined' && propertyValue.value !== null && 
 
       propertyValue.value !== "") { 
 
       data[property] = propertyValue.value; 
 
      } else if (typeof initialData !== 'undefined' && 
 
         typeof initialData[property] !== 'undefined') { 
 
       data[property] = initialData[property]; 
 
      } 
 
     } 
 

 
     return data; 
 
    } 
 

 
    reset() { 
 
     for (let field in this.originalData) { 
 
      this[field] = ''; 
 
     } 
 

 
     typeaheads = document.querySelectorAll('[id^="typeahead"]'); 
 
     for (let item in typeaheads) { 
 
      typeaheads[item].value = ''; 
 
     } 
 

 
     this.errors.clear(); 
 
    } 
 

 
    post(url) { 
 
     return this.submit('post', url); 
 
    } 
 

 
    put(url) { 
 
     return this.submit('put', url); 
 
    } 
 

 
    submit(requestType, url) { 
 
     return new Promise((resolve, reject) => { 
 
      axios[requestType](url, this.data()) 
 
       .then(response => { 
 
        this.onSuccess(response.data); 
 
        resolve(response.data); 
 
       }) 
 
       .catch(error => { 
 
        this.onFail(error.response.data); 
 
        reject(error.response.data); 
 
       }); 
 
     }); 
 
    } 
 

 
    onSuccess(data) { 
 
     this.reset(); 
 
    } 
 

 
    onFail(errors) { 
 
     this.errors.record(errors); 
 
    } 
 
} 
 

 
module.exports = Form;

どのように私はこの問題を解決する必要があります。ここでは

は私のフォームクラスのコードですか?何か不足していますか?

答えて

0

あなたは、複雑なOjbectsの(フォーム)の属性の変化に反応するようにしてみてください。 Vueは、(UI)更新をトリガするプロパティにgetterおよびsetterを追加します。 https://vuejs.org/v2/guide/reactivity.html

あなたのケースでは、フォームアップデートのどこかで更新がレンダリング更新を実行するようにビューに通知されません。

v-on:category_id_typeahead="form.errors.clear('category_id')"は、別のメソッドwhickがform.errors.clear('category_id');を実行し、uiの更新をトリガーするものを呼び出さなければなりません。これは、変更されるhttps://vuejs.org/v2/api/#vm-forceUpdateまたは新しいdata:{showError:false...属性です。

関連する問題