Wczoraj, pisząc to pytanie, natknąłem się na prostą, krótką prezentację Vue przez YouTube i — chwilę wcześniej — skomponowaną odpowiedź na to pytanie.

W tym OP wymagał, aby ciąg tekstu, składający się z 1 i 0, był używany do generowania elementów <input type="checkbox"> i, w oparciu o wartość, aby te elementy były checked (dla wartości 1) lub niezaznaczone (dla wartości 0). Po filmie na YouTube przyszło mi do głowy, że można to wygenerować za pomocą Vue:

new Vue({
  el: 'div>form',
  data: {
    checkedStates: [
      [1, 0, 0, 1],
      [0, 0, 1, 1],
    ],
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div>
  <form>
    <div v-for="(state, index) in checkedStates" class="form-group">
      <label class="control-label" :for=`group${index}States`>Sequence of on/off:</label>
      <input :id=`group${index}States` type="text" :value="state.join('')" class="myCars">
      <ul>
        <li v-for="entry in state">
          <label>
          <input type="checkbox" :name=`group${index}` :checked="entry === 1">
        </label>
        </li>
      </ul>
    </div>
  </form>
</div>

Demo JS Fiddle.

Było to — jak można się było spodziewać — stosunkowo proste.

Jednak OP, w komentarzu do innej odpowiedzi, zapytał, czy możliwe jest zaktualizowanie wartości elementu <input type="text"> na podstawie interakcji użytkownika z polami wyboru. W tym miejscu – a do tej pory miałem mniej niż 24 godziny doświadczenia z Vue – utknąłem.

Moje początkowe założenie było takie, że powinienem użyć:

<input type="checkbox" :name=`group${index}` :checked="entry === 1" @change="state">
new Vue({
  el: 'div>form',
  data: {
    checkedStates: [
      [1, 0, 0, 1],
      [0, 0, 1, 1],
    ],
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div>
  <form>
    <div v-for="(state, index) in checkedStates" class="form-group">
      <label class="control-label" :for=`group${index}States`>Sequence of on/off:</label>
      <input :id=`group${index}States` type="text" :value="state.join('')" class="myCars">
      <ul>
        <li v-for="entry in state">
          <label>
          <input type="checkbox" :name=`group${index}` :checked="entry === 1" @change="state">
        </label>
        </li>
      </ul>
    </div>
  </form>
</div>

To z pewnością stworzyło wymaganą procedurę obsługi zdarzeń zmiany, ale spowodowało błąd:

vue.min.js:6 Uncaught TypeError: n[r].apply is not a function
  at i (vue.min.js:6)
  at HTMLInputElement.Rr.t._withTask.o._withTask (vue.min.js:6)

(Chrom 70.x, Ubuntu 18.04)

Założenie opierało się na błędnym (najwyraźniej) przekonaniu, że powiązanie danych state z obsługą zdarzeń zaktualizuje te dane.

Oczywiście obsługa zdarzeń oczekuje funkcji. Zmieniłem więc moje podejście do:

<input type="checkbox" :name=`group${index}` :checked="entry === 1" @change="updateState()">

Wraz ze zaktualizowanym wywołaniem Vue:

new Vue({
  el: 'div>form',
  data: {
    checkedStates: [
      [1, 0, 0, 1],
      [0, 0, 1, 1],
    ],
  },
  methods: {
    updateState(){
      console.log(this.checkedStates);
    }
  },
});

Był to krok weryfikacyjny, aby upewnić się, że wywołanie funkcji działa, dlatego zasadniczo nie robi nic poza console.log(); w tym momencie zdałem sobie sprawę, że mogę uzyskać dostęp do tablicy checkedStates tablic, ale nie miałem pojęcia, jak określić, które z zagnieżdżonych tablic należy zaktualizować.

Ostatecznie doszedłem do punktu, w którym użyłem różnych indeksów zaśmieconych w całym kodzie HTML oraz w wywołaniu funkcji, i skończyło się na:

new Vue({
  el: 'div>form',
  data: {
    checkedStates: [
      [1, 0, 0, 1],
      [0, 0, 1, 1],
    ],
  },
  methods: {
    updateState(i,n) {
      console.log(this.checkedStates[i][n]);
    }
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div>
  <form>
    <div v-for="(state, stateIndex) in checkedStates" class="form-group">
      <label class="control-label" :for=`group${stateIndex}States`>Sequence of on/off:</label>
      <input :id=`group${stateIndex}States` type="text" :value="state.join('')" class="myCars">
      <ul>
        <li v-for="(entry, entryIndex) in state">
          <label>
          <input type="checkbox" :name=`group${stateIndex}` :checked="entry === 1" @change="updateState(stateIndex, entryIndex)" v-model="entry">
        </label>
        </li>
      </ul>
    </div>
  </form>
</div>

Wiersz console.log() w metodzie updateState() rejestruje znak w poprawnym indeksie poprawnej tablicy; nie aktualizuje — jak sądzę — w przewidywalny sposób — tej wartości do 1 (zaznaczone) lub 0 (niezaznaczone).

Kod również stał się, a przynajmniej staje się, ohydnym bałaganem; co prowadzi mnie do przekonania, że ​​nie patrzę na problem właściwie.

Dokumentacja Vue (https://vuejs.org/v2/guide/forms.html# Pole wyboru) wydaje się sugerować, że użycie v-model="entry" powinno działać:

<input type="checkbox" :name=`group${stateIndex}` :checked="entry === 1" @change="updateState(stateIndex, entryIndex)" v-model="entry">

Ale to zostało użyte powyżej i chociaż nie wydaje się generować żadnego błędu, nie aktualizuje również tablicy entry; w tym, że wydaje się, że aktualizacje tego Array byłyby/powinny być automatycznie odzwierciedlone w wartości elementu <input>.

Więc mój problem jest prawdopodobnie oparty na błędnych założeniach, a także na całkowitym braku doświadczenia z Vue.

Ale, to powiedziawszy, moje pytanie brzmi:

Jak mogę używać Vue, aby umożliwić:

  1. Ciąg tekstu w <input>, pochodzący z tablicy checkedStates obiektu data do generowania i zaznaczania/odznaczania elementów <input type="checkbox">, oraz
  2. W jaki sposób można zaktualizować wartość <input>, aby odzwierciedlała zaznaczenie/odznaczenie przez użytkownika utworzonych elementów pola wyboru?
0
David Thomas 3 listopad 2018, 18:15

1 odpowiedź

Najlepsza odpowiedź

Twoja logika jest rozsądna i idziesz tutaj we właściwym kierunku. Jedynym problemem, jak powiedziałeś, jest twoja nieznajomość Vue. Dzięki niewielkim modyfikacjom możesz to uruchomić ...

new Vue({
  el: 'div>form',
  data: {
    checkedStates: [
      [1, 0, 0, 1],
      [0, 0, 1, 1],
    ],
  },
  methods: {
    updateState(state, index, event) {
      this.$set(state, index, event.target.checked ? 1 : 0)
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div>
  <form>
    <div v-for="(state, index) in checkedStates" class="form-group">
      <label class="control-label" :for=`group${index}States`>Sequence of on/off:</label>
      <input :id=`group${index}States` type="text" :value="state.join('')" class="myCars">
      <ul>
        <li v-for="(entry, entryIndex) in state">
          <label>
          <input type="checkbox" :name=`group${index}` :checked="entry === 1" @change="updateState(state, entryIndex, $event)">
          </label>
        </li>
      </ul>
    </div>
  </form>
</div>

JSFiddle

Wyjaśnienie (z komentarzy):

W Vue możesz przekazać zdarzenie do swojego modułu obsługi zdarzeń w swoim szablonie za pomocą $słowo kluczowe wydarzenia. Dla natywnych zdarzeń DOM emitowanych przez normalne elementy HTML jest to zwykły obiekt zdarzenia. W przypadku zdarzeń niestandardowych będzie to ładunek emitowany ze zdarzeniem niestandardowym. Zauważ, że jeśli wywołasz obsługę zdarzeń bez żadnych argumentów, $event zostanie automatycznie przekazany jako jedyny argument.

Po przechwyceniu emitowanej wartości i przekazaniu jej do handlera możesz użyć jej do zmodyfikowania swojej tablicy stanów. Ale Vue nie może wykryć modyfikacji tablicy, gdy masz bezpośredni dostęp do jej elementów . Dlatego musisz użyć Vue.set (lub jego aliasu vm.$set), aby zachować reaktywność

2
David says reinstate Monica 3 listopad 2018, 21:34