2015-05-08 25 views
24

Oświadczenie: To jest moja pierwsza próba zbudowania aplikacji MVVM. Nie pracowałem wcześniej z Vue.js, więc możliwe, że mój problem jest wynikiem bardziej fundamentalnego problemu .Vue JS Oglądanie głęboko zagnieżdżonego obiektu


Moim zdaniem mam dwa rodzaje bloków z wyboru:

  • Typ 1: bloku/wyboru
  • Typ 2: block/nagłówki/pól wyboru

Podstawowa Obiekt ma następującą strukturę:

{ 
    "someTopLevelSetting": "someValue", 
    "blocks": [ 
    { 
     "name": "someBlockName", 
     "categryLevel": "false", 
     "variables": [ 
     { 
      "name": "someVarName", 
      "value": "someVarValue", 
      "selected": false, 
      "disabled": false 
     } 
     ] 
    }, 
    { 
     "name": "someOtherBlockName", 
     "categryLevel": "true", 
     "variables": [ 
     { 
      "name": "someVarName", 
      "value": "someVarValue", 
      "categories": [ 
      { 
       "name": "SomeCatName", 
       "value": "someCatValue", 
       "selected": false, 
       "disabled": false 
      } 
      ] 
     } 
     ] 
    } 
    ] 
} 

Moje cele

wszystkich zaznaczając:

  1. użytkownik klika pole wyboru, pole zostanie wybrany (wybrane = true)
  2. Sposób wypala się, by sprawdzić, czy wszelkie inne pola wyboru muszą być wyłączone (wyłączone = true). (Jeśli ta metoda rzeczywiście wyłączone niczego, ale także zwraca się ponownie, ponieważ inne przedmioty mogą być z kolei zależy od pozycji wyłączone)
  3. Inna metoda aktualizuje kilka innych rzeczy, takich jak ikony itp

Usuwanie wyboru

Użytkownik może kliknąć przycisk "wyczyść", który odznacza wszystkie pola wyboru na liście (selected = false). Działania te powinny również wywołać metody, które ewentualnie wyłącza wyboru i aktualizuje ikony itp

Moja obecna metoda(co nie wydaje się całkiem w porządku)

  • wybranego atrybutu z Dane- model jest związany z sprawdzonym stanem elementu checkbox za pomocą dyrektywy v-model.
  • Wyłączony atrybut (z modelu) jest powiązany z klasą elementu i wyłączonym atrybutem. Ten stan jest ustalany za pomocą wyżej wymienionej metody.
  • Aby zainicjować metody, które wyłączają pola wyboru i zmieniają niektóre ikony, używam dyrektywy v-on="change: checkboxChange(this)". Chyba muszę zrobić tę część inaczej metoda
  • clearList jest wywoływana poprzez v-on="click: clearList(this)"

problemów z mojej obecnej konfiguracji jest to, że wydarzenie zmiana nie jest wypalania gdy pola wyboru są wyczyszczone programowo (tj nie przez interakcje użytkownika).

Chciałbym zamiast
mi się najbardziej logicznym rozwiązaniem byłoby wykorzystanie this.$watch i śledzić zmiany w modelu, zamiast słuchać zdarzeń DOM.

Gdy pojawi się zmiana, będę musiał zidentyfikować, który dokładnie element się zmienił i działać w tym kierunku. Próbowałem utworzyć funkcję $watch, która obserwuje macierz blocks. Wydaje się, że zmienia się to dobrze, ale zwraca cały obiekt, w przeciwieństwie do pojedynczego atrybutu, który się zmienił. Również ten obiekt nie ma wygodnych atrybutów pomocniczych, takich jak $parent.

Mogę wymyślić kilka hackowatych sposobów na to, aby aplikacja działała (np. Ręczne wywoływanie zdarzeń zmiany w mojej metodzie clearList itp.), Ale mój przypadek użycia wydaje się dość standardowy, więc spodziewam się, że istnieje prawdopodobnie o wiele bardziej elegancki sposób załatw to.

Odpowiedz

7

Ponieważ nikt nie odpowiedział, a ja rozwiązałem/rozwiązałem problem, doszedłem do wniosku, że warto opublikować moje rozwiązanie. Proszę zauważyć, że nie jestem pewien, czy moje rozwiązanie polega na tym, jak należy rozwiązywać takie problemy, ale działa.

Zamiast używać tego detektora zdarzeń v-on="change: checkboxChange(this)" Używam teraz dyrektywy niestandardowej, która nasłuchuje zarówno wybranego, jak i wyłączonego atrybutu modelu, na przykład: v-on-filter-change="selected, disabled".

Dyrektywa wygląda następująco:

directives: { 
    'on-filter-change': function(newVal, oldVal) { 
     // When the input elements are first rendered, the on-filter-change directive is called as well, 
     // but I only want stuff to happen when a user does someting, so I return when there is no valid old value 
     if (typeof oldVal === 'undefined') { 
      return false; 
     } 
     // Do stuff here 
     // this.vm is a handy attribute that contains some vue instance information as well as the current object 
     // this.expression is another useful attribute with which you can assess which event has taken place 
    } 
}, 

if klauzula wydaje się nieco hacky, ale nie mogłem znaleźć inny sposób. Przynajmniej wszystko działa.

Być może przyda się to komuś w przyszłości.

55

Można użyć „zegarka” metodę .. na przykład jeśli dane są:

data: { 
    block: { 
     checkbox: { 
      active:false 
     }, 
     someotherprop: { 
      changeme: 0 
     } 
    } 
} 

Można zrobić coś takiego:

data: {...}, 
watch: { 
    'block.checkbox.active': function() { 
     // checkbox active state has changed 
     this.block.someotherprop.changeme = 5; 
    } 
} 
+1

.selected i .disabled są właściwościami anonimowych zmiennych, które należą do tablicy zmiennych. Twój przykład działa, ponieważ jest to tylko pojedynczy obiekt, a nie tablica. – Hendrik

+0

Zrobiłem coś w rodzaju block.checkbox.active, ale to nie działa, dopóki nie dodaję ich w "" jak wspomniałeś powyżej. Dzięki. Teraz działa. –

5

Jeśli chcesz obejrzeć obiekt jako całość ze wszystkimi jego właściwościami, a nie tylko jednego obiektu, można to zrobić w zamian:

data() { 
    return { 
     object: { 
      prop1: "a", 
      prop2: "b", 
     }  
    } 
}, 
watch: { 
    object: { 
     handler(newVal, oldVal) { 
      // do something with the object 
     }, 
     deep: true, 
    }, 
}, 

zawiadomienie handler i deep: true

+0

Dzięki za to. Ponieważ moje pytanie ma ponad dwa lata, a od tego czasu nie używam Vue, nie mogę zweryfikować, czy to działa. – Hendrik

+1

@Hendrik nie martw się, mam nadzieję, że to pomoże komuś, kto ma ten sam problem – peerbolte

+0

Czy wiesz, co powinienem zrobić, jeśli chcę tylko oglądać 'prop1'? –

2

Inne rozwiązanie niewymienione tutaj: Użyj opcji deep.

watch:{ 
    block: { 
    handler: function() {console.log("changed") }, 
    deep: true 
    } 
} 
Powiązane problemy