M.Koops
M.Koops

Reputation: 155

Vue.js form with v-if not hidden when showFormBoolena is set to false

I have parentform with a child form that allows to add games. The childform has option to edit games, and the grandchildform has option to add cards to the game, using a Imageupload component.

The idea is that admin can add cards using the cardform, whic is opened by clicking: add card, and which must close when card is added. Then the list of existing must be refreshed ( does not woreither, ...)

When I add a card to a game, and this is succesfull I set ShowCardForm=false, but this is not changed in the devtools VUE window.

While console shows that "ShowCardForm must be false now: false", as expected from the code.

I have been messing around for hours now, can anyone see what I am missing? (ChatGPT was a great help either...)

Here is part of the script:

  alert('Card added/updated successfully');
           
            this.showCardForm = false;
            console.log('ShowCardForm must be false now:', this.showCardForm);

            this.resetForm(); 

Can anyone see how I can solve this?

Here is the whole script: GameAdmin:

<template>
<Navibar ></Navibar> 


<div class ="custom-container" >
    <br>
    <br>
    <div v-if="!showGameForm"  class="text-center">
        
        
        <h2>Game-beheer </h2>
        <button  @click="toggleShowGameForm" class="btn btn-info m-1">Nieuw spel maken</button>
    </div>
     <div class="card text-center card-bg" v-if="showGameForm">
        <div class="card-body">
            <form  class="mb-3"   > 
                <div class="row">
                    <div class="col">
                        <label><h4> Gamenaam: </h4></label>
                    </div>
                    <div class="col">
                        <input type="text" class="form-control" placeholder="naam" v-model="game.naam">
                    </div>
                </div>
                    
    
                <div class="mt-2">
                    <div class="row">
                    <div class="col">
                        <label><h4> Stel de status in: </h4></label>
                    </div>
                    <div class="col">
                        <div class="d-flex justify-content-around">
                        <input class="btn-check" type="radio" name="game_status" id="closed" v-model="game.game_status" value="closed">
                        <label class="btn btn-outline-primary" for="closed"> Niet actief </label>
                        <input class="btn-check" type="radio" name="game_status" id="open" v-model="game.game_status" value='open' checked="checked">
                        <label class="btn btn-outline-primary" for="open"> Kaarten maken </label>
                        <input class="btn-check" type="radio" name="game_status" id="actief" v-model="game.game_status" value="actief">
                        <label class="btn btn-outline-primary" for="actief"> Actief </label>
                        <br>
                    </div>
                </div>
                </div>
                    
                    
                </div>
                <br><br>

                 <div class="d-flex justify-content-between align-items-center">
                    <button @click="toggleShowGameForm" class="btn btn-info">Terug</button>
                    <button @click= "addgame" type="button" class="btn btn-primary">Save</button>
                </div>

                <ManageCards :key = "currentGame.id" v-if="currentGame && Object.keys(currentGame).length"></ManageCards>
            
            </form>
            
        </div>
    </div>

    <div v-if="!gamesExist">
        Er zijn nog geen games gemaakt.
        </div>
    <div v-if="!showGameForm && gamesExist">  <!-- Laat lijst met spellen zien als er geen editscherm van een bepaald spel open staat -->
        <div class="card text-center card-bg mt-2" v-for="game in games.slice().reverse()" v-bind:key="game.id" >   
            <div class="card-body m-2">
                <h5 class="card-title"> Gamenaam: {{game.naam}}   </h5>
                <ul class="list-group list-group-flush">
                    <!-- <li class="list-group-item">Modus: {{game.game_mode}}</li> -->
                    <li class="list-group-item">Status:  {{game.game_status}}</li>
                    <li class="list-group-item">Pin: {{game.pin}}</li>
                </ul>
            

                    
                <button @click="deletegame(game.id)" class="btn btn-danger m-1" style="width:100px;color:white">  Delete  </button>
                <button @click="toggleShowGameForm(); editgame(game)" class="btn btn-warning m-1" style="width:100px;color:black">  Edit  </button>
                <button @click="setCurrentGame(game.pin)" class="btn btn-warning m-1" style="width:100px;color:black">  Run  {{game.pin}}</button>
            </div>
        </div>
    </div>
</div>
</template>

<script>

import { mapState, mapActions } from 'vuex';

export default {

    mounted() {
        console.log('component mounted');
        this.$store.commit('SET_CURRENT_GAME', {}); // Ensure currentGame is initialized as an empty object
        this.getGames();
    },
      computed: {
        ...mapState([
        'games' , 'token','currentGame'
        ]),
        gamesExist() {
        return this.games && this.games.length > 0;
        }, 
    },
    data() {
        return{
           // games:[],
            game:{
                id:'',
                naam:'',
                game_mode:'',
                game_status:'',
                pin: 0,
            },
            game_id:'',
            edit:false,
            selected:'',
            showGameForm: false,
            currentGameError:false,
            checked:false,
            
        }

    },
    created(){
        //this.fetchgames();
          
    },
  
    methods: {

        ...mapActions([  'getGames', 'addGame',  'retrieveGameByPin' ]),

        toggleShowGameForm(){
            this.$store.commit('SET_CURRENT_GAME',{});
            this.game.naam='naam';
            this.game.game_mode='open';
            this.game.game_status='open';
            this.game.pin='0';
            this.showGameForm = !this.showGameForm;
        },

     
        async setCurrentGame(pin){
            console.log("ik krijg deze pin door:"+ pin);
           await this.retrieveGameByPin(pin)
            .then(res =>  {
                console.log('gelukt met pin' + pin)   // als status 200, dan resolvet de promise uit de action, and komen we hier uit
                console.log("retrievegamebypin result == " + JSON.stringify(res));
            })  
            .catch(err => {
                //this.currentGameError = true;
                console.error(err);
            });
      
        },

        // DELETE GAME WERKT NOG NIET, KAN PAS ALS ALLE CARDS OOK VERWIJDERD ZIJN..
        deletegame(id){
            if(confirm('Are you sure?')){
               const formData = new FormData();
               formData.append('_method', 'DELETE');  // axios setting
               const config = {
                    headers: { Authorization: `Bearer `+ this.token} 
                };
                axios.post(`../api/games/${id}`,
                    formData,
                    config
                )
                //.then(res => res.json())
                .then(data => {
                    // De game is verwijderd, nu vernieuw de lijst met games
                    this.getGames()
                     .then(res => { 
                        console.log(res);
                    })
                    .catch(err => {
                        console.log(err);
                    });
                })
                .catch(err => console.log(err));
            }

        },
        addgame(){
            // de informatie voor de game staat inthis.$game, nu omzetten naar FormData om file toe te voegen aan de request zodat api die kan opslaan, api gaat ook naam bedenken voor de game.
            //  via fetchgames() komt die naam dadelijk terug in game.picture
            const formData = new FormData();
            formData.append('naam',this.game.naam);
            formData.append('game_mode',this.game.game_mode);
            formData.append('game_status',this.game.game_status);
            //formData.append('pin',this.game.pin); //this.game.pin);
            //formData.append('user_id', 11); //this.game.user_id); dit wordt aan de hand van de api-token op de server ingevuld
         

            if(this.edit === false){
                //add
                console.log("adding" +  formData);
                this.addGame(formData)
                .then(data => {
                    this.game.naam='';
                    this.game.game_mode='';
                    this.game.game_status='';
                    this.game.pin='';
                   // this.game.user_id='';   dit wordt aan de hand van de api-token op de server ingevuld
                    this.showGameForm=false;
                    //alert('game added');
                    this.getGames()
                    .then(res => { 
                        console.log(res);
                    })
                    .catch(err => {
                        console.log(err);
                    });
                })
                .catch(err => console.log(err));
            } else{
                //update
                console.log("updating");
                formData.append('_method', 'PUT');  // axios setting
                const config = {
                    headers: { Authorization: `Bearer ${this.token}` }
                };
                axios.post(`../api/games/${this.game.id}`,
                    formData, 
                    config
                )
                .then(res => console.log(res))
                .then(data => {
                    this.game.naam='';
                    this.game.game_mode='';
                    this.game.game_status='';
                    alert('game updated_admin.vue');
                        this.getGames();
                })
                .catch(err => console.log(err));
            }
        },
        editgame(game){
            this.currentGame = this.retrieveGameByPin(game.pin);
            this.edit=true;
            this.game.id=game.id;
            this.game.game_id=game.id;
            this.game.naam=game.naam;
            this.game.game_mode=game.game_mode;
            this.game.game_status=game.game_status;
            this.game.pin=game.pin;
        },

    }
}
</script>

ManageCards:

<template>
    <div class="custom-container" v-if="currentGame.id != undefined">
      <!-- Container wordt alleen weergegeven als er een currentGame is -->
      <div class="text-center">
        <br><br>
        <!-- Weergeven van de naam van het huidige spel -->
        <h1>{{ currentGame.naam }}</h1>
        <!-- Knop om het formulier voor het maken van een nieuwe kaart te tonen/verbergen -->
        <button type="button" @click="toggleShowCardForm" class="btn btn-info m-1">Nieuwe kaart maken</button>
  
        <!-- Formulier voor het maken/bewerken van een kaart -->
        <div class="card text-center card-bg" v-if="showCardForm">
          <h5 class="card-header">Kaart</h5>
          <div class="card-body">
            <form class="mb-3" >
              <div class="form-group">
                <!-- Beschrijving van de kaart -->
                <h4>{{ card.description }}</h4>
                <!-- Tekstveld voor het bewerken van de beschrijving -->
                <textarea class="form-control" :placeholder="card.description" v-model="card.description"></textarea>
              </div>
              <div>
                <!-- Voorbeeldweergave van de afbeelding van de kaart -->
                <img v-if="card.picture" class="img-circle" style="width:150px" :src="card.picture"/>
              </div>
              <div id="preview">
                <h4> Preview</h4>
                <!-- Component voor het uploaden van afbeeldingen -->
                <ImageUpload ref="imageUpload" :imgUrl="url" @newPicture="updatePicture"></ImageUpload>
              </div>
              <br>
              <!-- Knop om de kaart op te slaan -->
              <button @click="addCard();" type="button" class="btn btn-primary btn-block" style="color:white">Save</button>
            </form>
          </div>
        </div>
      </div>
  
      <!-- Lijst van kaarten -->
      <div v-for="card in cards" :key="card.id">
        <div class="card text-center card-bg mt-2">
          <div class="card-body mb-2" style="width: 100%">
            <div class="row">
              <div class="col">
                <!-- Beschrijving van de kaart -->
                <h3>{{ card.description }}</h3>
              </div>
              <div class="col">
                <!-- Afbeelding van de kaart -->
                <img class="img-circle" style="width:150px" :src="card.picture" alt="Card Image">
              </div>
              <div class="col">
                <br>
                <!-- Knoppen voor het verwijderen en bewerken van de kaart -->
                <span @click="deleteCard(card.id)"><i class="bi bi-trash m-1"></i></span>
                <span @click="editCard(card)"><i class="bi bi-pencil m-1"></i></span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </template>
  
  <script>
  import { mapState, mapActions } from 'vuex';
  import axios from 'axios';
  import ImageUpload from './ImageUpload.vue';
  
  export default {
    components: {
      ImageUpload, // Component voor het uploaden van afbeeldingen
    },

    watch: {
        showCardForm(newVal, oldVal) {
            console.log(`showCardForm changed from ${oldVal} to ${newVal}`);
        }
    },

    data() {
      return {
        card: {
          id: '', // ID van de kaart
          title: 'title', // Titel van de kaart
          description: 'naam', // Beschrijving van de kaart
          picture: '', // Afbeelding van de kaart
        },
        edit: false, // Boolean om te checken of we een kaart aan het bewerken zijn
        selectedFile: '', // Bestand geselecteerd voor uploaden
        showCardForm: false, // Boolean om het formulier te tonen/verbergen
        url: '', // URL van de geüploade afbeelding
        successMessage: '', // Bericht voor succesvolle bewerkingen
      };
    },

    computed: {
      ...mapState(['cards', 'currentGame', 'token']), // Vuex state voor kaarten, huidig spel en token
    },
    async mounted() {
      // Wanneer de component wordt geladen
      try {
        await this.getCards(this.currentGame.id); // Haal de kaarten op voor het huidige spel
        console.log('component mounted');
      } catch (error) {
        console.error('Error during mounted hook:', error);
      }
    },

    methods: {
      ...mapActions(['getCards']), // Vuex acties voor het ophalen van kaarten
      toggleShowCardForm() {
        this.showCardForm = !this.showCardForm; // Toon/verberg het formulier
        this.url = ''; // Reset de url wanneer het formulier wordt weergegeven of verborgen
        this.getCards(this.currentGame.id); // Haal opnieuw de kaarten op
      },
      async deleteCard(id) {
        // Verwijder een kaart
        if (confirm('Are you sure?')) {
          const formData = new FormData();
          formData.append('_method', 'DELETE'); // Methode voor het verwijderen instellen
          const config = {
            headers: { Authorization: `Bearer ${this.token}` }, // Configuratie voor de aanvraag met token
          };
  
          try {
            await axios.post(`../api/cards/${id}`, formData, config); // Verwijder kaart
            alert('Card removed');
            await this.getCards(this.currentGame.id); // Haal opnieuw de kaarten op
          } catch (error) {
            console.error('Error deleting card:', error);
          }
        }
      },
      async addCard() {
        // Voeg een nieuwe kaart toe of werk een bestaande kaart bij
        try {
          await this.$refs.imageUpload.setImage(); // Zet de imageUrl naar de picture en sla de picture of als file
  
          if (!this.selectedFile) {
            alert('Please select an image file');
            return;
          }
  
          const formData = new FormData();
          formData.append('title', this.card.title); // Voeg de titel toe aan formData
          formData.append('description', this.card.description); // Voeg de beschrijving toe aan formData
          formData.append('imagefile', this.selectedFile); // Voeg de afbeelding toe aan formData
          formData.append('game_id', this.currentGame.id); // Voeg het spel-ID toe aan formData
  
          let response;
          if (!this.edit) {
            // Nieuwe kaart toevoegen
            response = await fetch(`api/cards`, {
              method: 'POST',
              body: formData,
            }).then(response => response.json());
          } else {
            // Bestaande kaart bijwerken
            formData.append('_method', 'PUT');
            const config = {
              headers: { Authorization: `Bearer ${this.token}` },
            };
            response = await axios.post(`../api/cards/${this.card.id}`, formData, config).then(res => res.data);
          }
  
          if (response && response.id) {
          
          
            alert('Card added/updated successfully');
           
            this.showCardForm = false;
            console.log('ShwoCardForm must be false now:', this.showCardForm);

            this.resetForm();
            
           
          } else {
            alert('Failed to add/update card');
          }
        } catch (error) {
          console.error('Error updating card:', error);
          alert('An error occurred while adding/updating the card');
        }
      },
      editCard(card) {
        // Zet de huidige kaart voor bewerking
        window.scrollTo(0, 0); // Scroll naar boven
        this.edit = true; // Zet edit mode aan
        this.showCardForm = true; // Toon het formulier
        this.card = { ...card }; // Kopieer de kaartgegevens
      },
      updatePicture(imageData) {
        // Werk de afbeelding bij
        this.selectedFile = imageData.file; // Zet het geselecteerde bestand
        this.card.picture = imageData.picture; // Zet de afbeelding URL
      },
      resetForm() {
        // Reset het formulier
        this.card = {
          id: '',
          title: '',
          description: '',
          picture: '',
        };
        this.url = ''; // Reset de URL
        this.edit = false; // Zet edit mode uit
      },
    },
  };
  </script>
  

and IMageUpload:

<template>
    <div class="Image-Upload-wrapper Image-upload"> 
        <div>
                <input type="file" v-on:change="onFileChange" ref="fileUpload" id="file_picture_input">
                <label for ="file_picture_input" class="upload_picture_button"> Kies afbeelding</label>
        </div>
       

       <div id="croppie"> </div>     

       <div class="upload-wrapper">
            <!-- type="button"" anders vervest de knop de hele pagina " -->  
            <!-- <button type="button" class="btn btn-primary btn-sm" v-on:click="setImage"> SetImage!  </button>-->
        </div>   
 
    </div>
</template>



<script>
//  uitleg over Croppie::https://www.youtube.com/watch?v=kvNozA8M1HM
import Croppie from 'croppie';

export default {
    props:[
        'imgUrl'
    ],
    emits:['newPicture'
    ],
    mounted(){
              this.setUpCroppie()
    },
    data(){
        return{
           croppie:null,
           croppieImage:'',
           selectedFile:'',
           picture:'',
           url:this.imgUrl || '',
        }
    },
    //Zorg ervoor dat imgUrl updates correct worden doorgegeven aan Croppie.
    watch: {
        imgUrl(newVal) {
            if (newVal) {
                this.url = newVal;
                this.croppie.bind({ url: newVal });
            }
        }
    },
    methods:{
        setUpCroppie(){
           let el = document.getElementById('croppie');
           this.croppie = new Croppie(el, {
               viewport:{width:200,height:200,type:'circle'},
               boundary:{ width:220,height:220},
               showZoomer:true,
               enableOrientation: true
           });
           this.croppie.bind({       
               url:this.url
           })
           .catch(error => console.error('Error binding croppie with url:', error));
        },
        setImage(){
            return this.croppie.result({
                type:'canvas',
                size:'viewport'
            })
            .then(blob =>fetch(blob))
            .then(res => {return res.arrayBuffer();})
            .then(buf => {return new File([buf], this.croppieImage.name, {type:'image/png'});})
            .then(file => { 
                this.croppieImage = file;
                this.picture = URL.createObjectURL(this.croppieImage);
                const imageData={
                    picture:this.picture, 
                    file: this.croppieImage
                };
                console.log("klaar voor emit...?");
                this.$emit('newPicture', imageData);
                this.url='';
            })
            .catch(error => {
            console.error("Error setting image:", error);
            });
        },
        onFileChange(e){ 
            if (e.target.files && e.target.files.length > 0) {
                this.selectedFile = e.target.files[0];
                console.log("gekozen file is: " + this.selectedFile.name);
                this.url = URL.createObjectURL(this.selectedFile);
                this.croppie.bind({
                    url: this.url
            })
            .catch(error => console.error('Error binding croppie with file url:', error));
             } else {
            // Geen afbeelding geselecteerd, instellen op een standaardwaarde (bijv. een lege string)
            this.selectedFile = null;
            this.url = '';
            }
        },
        reset() {
            this.selectedFile = null;
            this.picture = '';
            this.url = '';
            this.croppie.bind({
                url: ''
            }).catch(error => console.error('Error binding croppie with reset url:', error));
        }
    },
  
}
</script>

Upvotes: 0

Views: 38

Answers (0)

Related Questions