Attribute not re-rendered after @change method in input file

I am trying to update an attribute after @change event on input file but I can’t render the updated value on the Vue.js Template.

I can only console log it and it works after setting value.

The problem is inside @change=“setVideo” on the input field and the attribute is “videoUrl” that is not updated on the template after the event

<template>
  <ion-page id="board">

    <ion-content ref="feedContent">


      <ion-refresher slot="fixed" @ionRefresh="reloadFeed($event)">
        <ion-refresher-content></ion-refresher-content>
      </ion-refresher>


      <ion-list id="feed">
        <ion-card class="ion-padding">

          <ion-item-divider color="none">
            <MentionableTextarea :key="mentionable"
                                 @onFocus="toggleFloat"
                                 @onBlur="toggleFloat"
                                 :items="userFriends"
                                 v-model:modelValue="form.text"
                                 v-model:selectedIds="form.taggedFriends"
                                 :placeholder="loggedUser.name+', raccontaci l\'ultima partita...'"/>
            <ColorPicker v-model="form.background"/>

          </ion-item-divider>

          <ion-grid>
            <ion-row>

              <ion-col size="12" v-if="previewImage">
                <ion-button size="small" @click="previewImage = null" style="position:absolute;top:10px;right:10px;">
                  Elimina
                </ion-button>
                <ion-img v-if="previewImage" :src="previewImage"></ion-img>
              </ion-col>


            <!--  <ion-col size="12" v-if="videoUrl">
                <ion-button size="small" @click="videoUrl = null" style="position:absolute;top:10px;right:10px;">
                  Elimina
                </ion-button>
                <video style="width:100%" playsinline preload="auto" id="video">
                  <source type="video/mp4" :src="videoUrl">
                  Your browser does not support the video tag.
                </video>
              </ion-col>-->

              {{ videoUrl }}

              <input
                  style="display:none"
                  type="file"
                  accept="video/mp4, video/x-m4v, video/*"
                  capture
                  @change="setVideo"
                  id="open-camera"
              />
              <input
                  style="display:none"
                  type="file"
                  accept="video/mp4, video/x-m4v, video/*"
                  @change="setVideo"
                  id="open-gallery"
              />
            </ion-row>
          </ion-grid>
          <ion-button v-if="!liveSession" size="full" @click="_addPost(form)" class="ion-margin-top">
            Pubblica
          </ion-button>


        </ion-card>
      </ion-list>

      <ion-list id="feeds">
        <post-feed v-on:toggle-float="toggleFloat" v-on:deleted="onPostDeleted" v-on:shared="reloadFeed($event)"
                   v-for="post of feeds" :key="'post_'+post.id"
                   v-on:start-friend_live="startFriendLive"
                   :user-friends="userFriends"
                   :post="post"></post-feed>
      </ion-list>

      <ion-infinite-scroll
          v-if="currentPage <= maxPage"
          @ionInfinite="getUserFeed"
      >
        <ion-infinite-scroll-content
            loadingSpinner="bubbles"
            loadingText="Carico altri post…">
        </ion-infinite-scroll-content>
      </ion-infinite-scroll>

      <ion-modal
          :is-open="isRegisterPositionModalOpen"
      >
        <RegisterPosition @onDidDismiss="isRegisterPositionModalOpen = false" @onSave="onSaveRegisterPosition"/>
      </ion-modal>


    </ion-content>

    <ion-fab v-if="!writeMode" horizontal="end" vertical="bottom" slot="fixed">

      <ion-fab-button class="gradient">
        <i class="fas fa-2x fa-plus"></i>
      </ion-fab-button>

      <ion-fab-list side="start">

        <ion-item-group style="margin-top:-190px">
          <ion-item button @click="onPictureTaken">
            <ion-label>
              <i class="fas fa-camera"></i>
              Carica foto
            </ion-label>
          </ion-item>
          <ion-item button @click="openVideo">
            <ion-label>
              <i class="fas fa-video"></i>
              Registra video
            </ion-label>
          </ion-item>
          <ion-item button @click="openGallery">
            <ion-label>
              <i class="fas fa-video"></i>
              Upload video
            </ion-label>
          </ion-item>
          <ion-item button @click="isRegisterPositionModalOpen = true">
            <ion-label>
              <i class="fas fa-map-marker"></i>
              Registrati
            </ion-label>
          </ion-item>
          <ion-item button @click="$router.push({name:'AddEvent'})">
            <ion-label>
              <i class="far fa-calendar-alt"></i>
              Crea evento
            </ion-label>
          </ion-item>

          <ion-item button @click="openModal">
            <ion-label>
              <i class="fas fa-video"></i>
              Live Streaming
            </ion-label>
          </ion-item>
        </ion-item-group>


      </ion-fab-list>
    </ion-fab>


    <ion-modal
        :is-open="isLiveActive"
    >
      <ion-page>
        <ion-header>
          <ion-toolbar>
            <ion-title v-if="livePost && livePost.user_id == loggedUser._id">
              Sei in diretta
            </ion-title>
            <ion-title v-if="livePost && livePost.user_id != loggedUser._id">Live</ion-title>
            <ion-buttons slot="end">
              <ion-button @click="disconnectLive()">Termina</ion-button>
            </ion-buttons>
          </ion-toolbar>
        </ion-header>
        <ion-content class="ion-padding">
          <div id="publisher" style="width:100%;height:300px"></div>
          <ion-button v-if="livePost && livePost.user_id == loggedUser._id" @click="changeCamera()">Cambia Camera
          </ion-button>
          <ion-grid>
            <ion-row>

              <ion-col size="12">
                <ion-textarea placeholder="Scrivi il tuo commento..."
                              v-model="newCommentLive"></ion-textarea>
                <ion-button @click="addCommentToLive()" type="submit" size="small" class="ion-margin-bottom">
                  Commenta
                </ion-button>
              </ion-col>

              <ion-col size="12">
                <ion-list-header style="padding-left:0px;" v-if="liveComments.length>0">Commenti</ion-list-header>
                <ion-list class="comments" style="height: 200px;
overflow: scroll;">
                  <ion-item class="ion-no-padding" :key="'_comment_'+comment.id"
                            v-for="comment of liveComments">
                    <ion-avatar style="margin-left:5px;" slot="start">
                      <ion-img v-if="comment.user"
                               :src="'https://api.largestadium.com/uploads/'+comment.user.avatar"></ion-img>
                      <ion-img v-else src="assets/img/placeholder.png"></ion-img>
                    </ion-avatar>
                    <ion-label>
                      <h3 class="ion-text-capitalize">{{ comment.user.first_name }} {{ comment.user.last_name }}</h3>
                      <p>{{ comment.comment }}</p>
                    </ion-label>

                    <!-- <ion-badge style="right: 15px;
 position: absolute;" @click="addLikeToComment(comment)" color="none" v-if="!comment.has_my_like">
                       <i class="far fa-heart"></i>
                     </ion-badge>
                     <ion-badge style="right: 15px;
 position: absolute;" @click="removeLikeFromComment(comment)" color="none" v-else>
                       <i class="fas fa-heart"></i>
                     </ion-badge>-->

                  </ion-item>
                </ion-list>
              </ion-col>
            </ion-row>
          </ion-grid>

        </ion-content>
      </ion-page>

    </ion-modal>


  </ion-page>

</template>

<script lang="ts">
import {
  IonContent,
  IonRefresher,
  IonRefresherContent,
  IonPage,
  IonHeader,
  IonListHeader,
  IonTitle,
  IonButtons,
  IonToolbar,
  IonAvatar,
  IonTextarea,
  IonInfiniteScroll,
  IonList,
  IonInfiniteScrollContent,
  IonCard,
  IonFab,
  IonFabButton,
  IonImg,
  IonItemDivider,
  IonItemGroup,
  IonLabel,
  IonFabList,
  IonItem,
  IonButton,
  IonModal,
  IonRow,
  IonCol,
  IonGrid,
  loadingController
} from '@ionic/vue';
import {defineComponent, ref} from 'vue';
import {auth} from "@/modules/auth";
import PostFeed from '../components/PostFeed.vue';
import RegisterPosition from "@/components/modals/RegisterPosition.vue";
import {store} from "@/modules/store";
import OT from '@opentok/client'
import {usePhotoGallery} from '@/composables/usePhotoGallery';
import {camera, trash, close} from 'ionicons/icons';
import {MediaCapture} from '@ionic-native/media-capture';
import ColorPicker from "@/components/common/ColorPicker.vue";
import MentionableTextarea from "@/components/common/MentionableTextarea.vue";
import eventHub from '../utils/eventHub'

export default defineComponent({
  name: 'Feed',
  components: {
    IonAvatar,
    IonTextarea,
    IonHeader,
    IonListHeader,
    IonTitle,
    IonToolbar,
    IonButtons,
    MentionableTextarea,
    ColorPicker,
    RegisterPosition,
    IonContent,
    IonPage,
    IonRefresher,
    IonRefresherContent,
    IonRow,
    IonCol,
    IonGrid,
    IonInfiniteScroll,
    IonList,
    IonItemDivider,
    IonInfiniteScrollContent,
    IonCard,
    IonFab,
    PostFeed,
    IonFabButton,
    IonImg,
    IonItemGroup,
    IonLabel,
    IonFabList,
    IonItem,
    IonButton,
    IonModal
  },
  data() {
    return {
      cameraPosition: 'front',
      session: null,
      livePost: null,
      friendLivePost: null,
      isLiveFriendActive: false,
      mentionable: 0,
      countLiveComponent: 0,
      newCommentLive: null,
      form: {
        text: null,
        attachment: null,
        place: null,
        coordinates: null,
        attachmentType: null,
        background: null,
        taggedFriends: [],
      },
      isPosting: false,
      previewImage: null,
      writeMode: false,
      isLiveActive: false,
      userFriends: []
    }
  },
  setup() {
    const {takePhoto} = usePhotoGallery();

    const {loggedUser} = auth()
    const {isSearchMode} = store()

    const feeds = ref([])
    const maxPage = ref(1)
    const currentPage = ref(1)
    const createLiveModal = ref(null);
    const isRegisterPositionModalOpen = ref(false)
    const feedContent = ref(null);
    const liveComments = ref([])
    const publisher = ref(null);
    const liveSession = ref(null);
    const videoUrl = ref(null);

    return {
      videoUrl,
      publisher,
      liveComments,
      liveSession,
      takePhoto,
      camera, trash, close,
      feeds,
      createLiveModal,
      feedContent,
      maxPage,
      currentPage,
      loggedUser,
      isRegisterPositionModalOpen,
      isSearchMode
    }
  },
  created() {
    this.getUserFeed()
    this.getUserFriends()
  },
  mounted() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const $vm = this
    eventHub.$on('reload-feed', () => {
      $vm.reloadFeed()
    })

  },
  methods: {
    startFriendLive(args) {
      this.createLive(args.post)
    },
    async openModal() {
      this.createLive()
    },
    /**
     * @desc Get user friends
     */
    async getUserFriends() {

      try {
        const response = await this.$http.get('/users/me/friends', {
          headers: {
            'Authorization': 'Bearer ' + localStorage.token
          }
        })
        this.userFriends = response.data.data

      } catch (error) {
        console.error(error)
      }
    },
    scrollToTop: function () {
      if (this.$refs.feedContent) {
        const content = (this.$refs.feedContent as any).$el
        content.scrollToTop(300)
      }
    },
    removeLikeFromComment(comment) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this
      this.$http.delete('/comments/' + comment.id + '/likes', {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token
        }
      })
          .then(() => {
            $vm.getLiveComments()
          });
    },
    addLikeToComment(comment) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this
      this.$http.post('/comments/' + comment.id + '/likes', {}, {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token
        }
      })
          .then(() => {
            $vm.getLiveComments()
          });
    },
    openVideo: function () {
      document.getElementById("open-camera").click();
    },
    openGallery: function () {
      document.getElementById("open-gallery").click();
    },

    addCommentToLive: function () {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this

      if ($vm.newCommentLive == '') {
        return false
      }


      this.$http.post('/posts/' + $vm.livePost.id + '/comments', {
        comment: $vm.newCommentLive
      }, {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token
        }
      }).then(function () {
        $vm.newCommentLive = ''
        $vm.getLiveComments()
      })
    },
    setVideo: function (event) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this
      $vm.videoUrl = 'asdasd'


    },
    getLiveComments: function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this

      if (!$vm.livePost) {
        return true
      }
      this.$http.get('/posts/' + $vm.livePost.id + '/comments', {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token
        }
      })
          .then((response) => {
            $vm.liveComments = response.data.data
            $vm.countLiveComponent += 1
          });
    },
    onPictureTaken: async function () {
      const picture = await this.takePhoto()

      this.form.attachment = picture.webPath
      this.form.attachmentType = 'image'

      this.previewImage = picture.webPath
      this.scrollToTop()

    },
    toggleFloat: function () {
      this.writeMode = !this.writeMode
    },
    onPickFile: function (id) {
      document.getElementById(id).click()
    },
    reloadFeed: function (event = null) {
      this.feeds = []
      this.currentPage = 1
      this.getUserFeed(event)
    },
    getUserFeed: function (event = null) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this

      this.$http.get('/posts?type=home&page=' + $vm.currentPage, {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token
        }
      })
          .then((response) => {
            if ($vm.feeds.length > 0 && $vm.currentPage == 1) {
              $vm.feeds = []
            }
            $vm.feeds = $vm.feeds.concat(response.data.data)
            $vm.maxPage = response.data.meta.last_page
            $vm.currentPage++
            if (event) {
              event.target.complete();
            }

          }, (error) => {
            console.log(error);
          });
    }

    ,
    /**
     * @desc On save register position
     */
    onSaveRegisterPosition(form) {
      this.isRegisterPositionModalOpen = false
      this._addPost(form)
    },
    disconnectLive: function () {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this
      this.isLiveActive = false
      this.liveComments = []

      $vm.liveSession.disconnect()

      if ($vm.loggedUser._id == $vm.liveSession.user_id) {
        this.$http.patch("/posts/" + $vm.livePost._id, {
              'is_live': true,
              'is_live_now': false,
              'text': $vm.loggedUser.name + ' ' + $vm.loggedUser.surname + ' era in diretta.'
            },
            {
              headers: {
                'Authorization': 'Bearer ' + localStorage.token
              }
            }).then(() => {
          $vm.livePost = null
          $vm.currentPage = 1
          $vm.feeds = []
          $vm.getUserFeed()
        })
      }


      this.liveSession = null
    },
    changeCamera: async function () {
      const loading = await loadingController
          .create({
            cssClass: 'my-custom-class',
            message: 'Cambio fotocamera in corso...',
          });

      await loading.present();

      this.cameraPosition = this.cameraPosition == 'front' ? 'back' : 'front'
      this.publisher.cycleVideo().then(async function () {
        await loading.dismiss()
      })

    },
    createLive: function (post = null) {
      this.isLiveActive = true
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this

      if (post) {
        $vm.livePost = post

        if (OT.checkSystemRequirements() == 1) {


          const session = OT.initSession('47130554', $vm.livePost.live_session_id);

          $vm.liveSession = session

          // Connect to the session
          session.connect($vm.livePost.live_token, function (error) {
            // If the connection is successful, publish to the session
            if (error) {
              console.log(error);
            } else {
              session.on('streamCreated', function (event) {

                session.subscribe(event.stream, 'publisher', {
                  insertMode: 'append',
                  width: '100%',
                  height: '100%'
                }, function (error) {
                  $vm.isLiveActive = true
                  setInterval(() => $vm.getLiveComments(), 2000);
                });

                session.on("streamDestroyed", function (event) {
                  $vm.disconnectLive()
                });

              });
            }
          })


        }
        return true
      }

      const formData = new FormData();
      formData.append("text", $vm.loggedUser.name + ' ' + $vm.loggedUser.surname + ' è in diretta.');
      formData.append("is_live", "true");
      formData.append("is_live_now", "true");

      this.$http.post('/posts', formData, {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token,
          'Content-Type': 'multipart/form-data'
        }
      })
          .then(async (response) => {

            $vm.livePost = response.data
            $vm.livePost.id = $vm.livePost._id

            const liveSession = OT.initSession(response.data.api_key, response.data.live_session_id);
            $vm.liveSession = liveSession

            // Subscribe to a newly created stream

            // Create a publisher
            const publisher = OT.initPublisher('publisher', {
              insertMode: 'append',
              width: '100%',
              height: '100%'
            }, function (e) {
              $vm.publisher = publisher
            });

            this.scrollToTop()


            // Connect to the session
            liveSession.connect(response.data.live_token, function (error) {
              // If the connection is successful, publish to the session
              if (error) {
                console.log(error);
              } else {
                liveSession.publish(publisher, function (e) {
                  $vm.isLiveActive = true
                  setInterval(() => $vm.getLiveComments(), 2000);


                  eventHub.$on('change-camera', () => {
                    $vm.changeCamera()

                  })

                });
              }
            });


          }, (error) => {
            console.log(error);
          });

    },
    onPostDeleted: function (id) {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this

      this.feeds.forEach(function (post, i) {
        if (post.id === id) {
          $vm.feeds.splice(i, 1)
        }
      });
    },
    /**
     * @desc add post action
     * @param form
     */
    async _addPost(form) {

      const loading = await loadingController
          .create({
            cssClass: 'my-custom-class',
            message: 'Pubblicazione in corso...',
          });

      await loading.present();

      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const $vm = this
      const formData = new FormData();
      formData.append("text", (form.text) ? form.text : '');
      formData.append("background", (form.background) ? form.background : '');

      formData.append("tagged_friends", JSON.stringify(form.taggedFriends));

      if (form.attachment) {
        let blob = null
        if (form.attachmentType == 'image') {
          blob = await fetch(form.attachment).then(r => r.blob());
        } else {
          blob = form.attachment
        }

        formData.append("attachment", blob);
        formData.append("attachmentType", form.attachmentType);


      }

      if (form.coordinates) {
        const coordinates = {lat: form.coordinates.lat, lng: form.coordinates.lng}
        formData.append("coordinates", JSON.stringify(coordinates));
        formData.append("location_name", form.place);
      }

      if (!form.text && !form.coordinates && !form.attachment) {
        return false
      }

      $vm.isPosting = true
      this.$http.post('/posts', formData, {
        headers: {
          'Authorization': 'Bearer ' + localStorage.token,
          'Content-Type': 'multipart/form-data'
        }
      })
          .then(async () => {
            await loading.dismiss()
            $vm.currentPage = 1
            $vm.form.text = ""
            $vm.form.background = null
            $vm.form.attachment = null
            $vm.previewImage = null
            $vm.videoUrl = null
            $vm.isPosting = false
            $vm.getUserFeed()
            $vm.scrollToTop()
            $vm.mentionable += 1

          }, (error) => {
            console.log(error);
          });
    }
  }
})
;
</script>```