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>```