Vue/Vuetify/v-model et édition d'entités

a marqué ce sujet comme résolu.

Bonjour !

La thématique du jour : maintenir la cohérence des données entre la création d’une entité et son édition ultérieure.

J’ai donc une entité Activity qui a notamment des Categories qui la définissent (des tags ou des labels, quoi, pour aider lors de la recherche).

Pour définir ces Categories, j’ai opté sur Vuetify pour des v-chip-group, avec comme v-model="activity.categories", ce qui me renvoie un Array, ça me convient très bien. C’est ce qui me semblait le plus logique et intuitif pour l’utilisateur : en créant l’activité on clique sur les "chips" qui conviennent. Puis on enregistre et ça marche. Youpi.

Le souci, c’est que je dois pouvoir éditer ces mêmes entités si on remarque une erreur. Là aussi, classique…mais ça ne marche pas.

Déjà, sur le formulaire d’édition, si j’utilise comme v-model="activity.categories", il ne me crée que les Chips qui sont déjà enregistrées pour cette entité. C’est normal, mais ce n’est pas le comportement voulu. Ce que je souhaite, c’est la liste complète des Chips de Category, cochés si ils sont associés à l’activité éditée. Ensuite, je souhaite cliquer sur les chips pour en ajouter ou enlever, puis mettre à jour l’Activité avec son nouveau set de Categories. Oui ? Pour compliquer le tout, j’utilise Symfony et Api Platform pour gérer les données, et donc mon activity.categories ne contient pas juste les IDs des catégories, mais tout un tas de données ajoutées par API Platform.

Si je fais ceci dans le template - notez la différence entre le v-model et le v-for :

<v-chip-group v-model="selectedCategories" multiple column @change="clickInfosChanged = true">
   <v-chip v-for="(category, index) in categories" :key="index" :value="category['@id']" filter>{{ category.name }}</v-chip>
 </v-chip-group>

J’ai bien ma liste complète des tags possibles, cochés si ils appartiennent à "selectedCategories", qui provient de Computed:

selectedCategories() {
   let array = [];
   for (let cat of this.activity.audiences) {
    array.push(cat['@id']);
   }
   return array;              
 },

Donc en apparence, j’ai ce que je veux, sauf que si je clique sur un des tags pour ajouter/enlever, ça ne fonctionne plus : [Vue warn]: Computed property "selectedCategories" was assigned to but it has no setter.

J’ai donc testé une variante avec getter et setter:

selectedCategories: {
      get: function() {
        let array = [];
        for (let cat of this.activity.categories) {
          array.push(cat['@id']);
        }
        return array;
      },
      set(value) {
        console.log(value);
      }
    },

Et je reçois très exactement ce que je veux dans la console : un array contenant les '@id' des chips cochés ou non. Mais je n’arrive pas à l’assigner ensuite à mon activité pour la mettre à jour:

let payload = {categories: this.selectedCategories};
console.log(payload.categories);

Cela me renvoie les données initiales de l’activité, et non celles mises à jour.

Tout ça pour demander :

Comment arranger la fonction "set" de selectedCategories pour assigner correctement this.activity.categories ?

Merci.

Edit : je précise que si je mets dans le setter "this.selectedCategories = value" et que je teste, j’ai une erreur [Vue warn]: Error in v-on handler: "InternalError: too much recursion"

+0 -0

J’ai trouvé une solution. Maintenant, je trouve ça extrêmement sale, alors si quelqu’un sait réellement comment utiliser Vue/Vuetify pour faire la même chose proprement, je suis complètement à l’écoute…

//Dans Data
test: [],

//Dans computed:
selectedCategories: {
      get: function() {
        let array = [];
        for (let cat of this.activity.categories) {
          array.push(cat['@id']);
        }
        return array;
      },
      set(value) {
        this.test = value;                  //C'est ça qui change
      }
    },

//Dans les methods pour l'envoi
let payload = {
  categories: this.test.length > 0 ? this.test : this.activity.categories.map(category => category['@id']),
}

Bon. Il doit y avoir moyen de faire mieux :p

Bon j’ai fait une meilleure version.

Mon souci vient du fait que API Platform renvoie forcément des infos supplémentaires dans une requête GET alors que je ne souhaite que l’info ['@id']. Du coup, Vue est perdu pour faire la corrélation entre ce qu’il attend pour gérer mes activity.categories - à savoir un array contenant des strings type "api/category/1" - et ce qu’il a réellement, à savoir un array d’Objects contenant entre autres l’info @id. Du coup, ma solution (meilleure ?) consiste dans le store de Vue de convertir automatiquement grâce à la fonction map l’objet Category en simple string @id.

On pourrait dire : mais pourquoi tu dis pas plutôt à API Platform de te renvoyer juste l'@id ? Simplement parce que je n’ai aucune idée sur la façon de faire ça, que donc que ça va me prendre une éternité à trouver dans la doc comment le faire, que j’ai peur de tout casser, et ce d’autant qu’au final, le cas où ça me pose un problème est ultra-ciblé et ultra-rare. Pour toutes les autres requêtes GET, j’ai effectivement besoin de toutes les infos qu’il renvoie.

Bref, c’est résolu, mais je ne suis pas satisfait.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte