How to use vuex with Konva for onDragEnd option - vue.js

I am using konva with vuex together.
This is a code at '~.vue' for defining image.
There are two options onDragEnd and onTransform in "const yo".
'this.msg' and 'this.msg2' for the two options is defined in methods.
Thus, I can use the two options on realtime.
/gallery.vue
.
.
created() {
const image = new window.Image();
image.src = this.imageUpload.url;
image.onload = () => {
const yo = {
image: image,
name: "yoyo",
draggable: true,
scaleX: this.imageUpload.positions.scaleX,
scaleY: this.imageUpload.positions.scaleY,
x: this.imageUpload.positions._lastPosX,
y: this.imageUpload.positions._lastPosY,
onDragEnd: this.msg,
onTransform: this.msg2
};
this.images.push(yo);
};
},
methods: {
msg(e) {
this.savePositions(e.target.attrs);
},
msg2(e) {
this.savePositions(e.currentTarget.attrs);
},
But I want to move the code inside of 'created()' into 'vuex store' to control by one file.
Therefore, I make that in vuex store again like below.
And when I call this actions into 'gallery.vue', everything works well except the two options function as 'this.msg' and 'this.msg2'.
I guessed the problem would happen from 'e' argument. And I edited with various methods.
But that functions doesn;t work saying this.msg and this.msg2 is not function.
How can I call this function correctly?
Thank you so much for your reading.
/store.js
.
.
const actions = {
bringImage({ commit }) {
axios
.get(`http://localhost:4000/work`)
.then(payload => {
commit('pushWorks', payload);
})
.then(() => {
const image = new window.Image();
image.src = state.url;
image.onload = () => {
// set image only when it is loaded
const yo = {
image: image,
name: state.title,
draggable: true,
scaleX: state.positions.scaleX,
scaleY: state.positions.scaleY,
x: state.positions._lastPosX,
y: state.positions._lastPosY,
onDragEnd: this.msg,
onTransform: this.msg2
};
state.images.push(yo);
};
});
},
msg({ commit }, e) {
commit('savePositions', e.target.attrs);
},
msg2({ commit }, e) {
commit('savePositions', e.currentTarget.attrs);
}
}

You don't have this in your actions. So try to dispatch your actions with e argument as a payload.
bringImage({
commit,
dispatch
}) {
axios
.get(`http://localhost:4000/work`)
.then(payload => {
commit('pushWorks', payload)
})
.then(() => {
const image = new window.Image()
image.src = state.url
image.onload = () => {
// set image only when it is loaded
const yo = {
image: image,
name: state.title,
draggable: true,
scaleX: state.positions.scaleX,
scaleY: state.positions.scaleY,
x: state.positions._lastPosX,
y: state.positions._lastPosY,
onDragEnd: e => dispatch('msg', e),
onTransform: e => dispatch('msg2', e),
}
state.images.push(yo)
}
})
}

Related

How to re-run useQuery and FlatList?

I use FlatList with useState.
const [state, setState] = useState(route);
<FlatList
keyboardDismissMode={true}
showsVerticalScrollIndicator={false}
data={state}
keyExtractor={(comment) => "" + comment.id}
renderItem={renderComment}
/>
When I change the datㅁ which is contained in state, I want to re-run Flatlist with new data.
So after I mutate my data, I try to rerun useQuery first in order to change state. I put refetch module here.
1)
const { data: updatePhoto, refetch } = useQuery(SEE_PHOTO_QUERY, {
variables: {
id: route?.params?.photoId,
},
});
If I put button, this onValid function will executed.
<ConfirmButton onPress={handleSubmit(onValid)}>
onValid function changes data and after all finished, as you can see I put refetch().
=> all this process is for that if I add comment and press confirm button, UI (flatlist) should be changed.
const onValid = async ({ comments }) => {
await createCommentMutation({
variables: {
photoId: route?.params?.photoId,
payload: comments,
},
});
await refetch();
console.log(updatePhoto);
};
But when I console.log data after all, it doesnt' contain added data..
what is the problem here?
If you need more explanation, I can answer in real time.
please help me.
add full code
export default function Comments({ route }) {
const { data: userData } = useMe();
const { register, handleSubmit, setValue, getValues } = useForm();
const [state, setState] = useState(route);
const [update, setUpdate] = useState(false);
const navigation = useNavigation();
useEffect(() => {
setState(route?.params?.comments);
}, [state, route]);
const renderComment = ({ item: comments }) => {
return <CommentRow comments={comments} photoId={route?.params?.photoId} />;
};
const { data: updatePhoto, refetch } = useQuery(SEE_PHOTO_QUERY, {
variables: {
id: route?.params?.photoId,
},
});
const createCommentUpdate = (cache, result) => {
const { comments } = getValues();
const {
data: {
createComment: { ok, id, error },
},
} = result;
if (ok) {
const newComment = {
__typename: "Comment",
createdAt: Date.now() + "",
id,
isMine: true,
payload: comments,
user: {
__typename: "User",
avatar: userData?.me?.avatar,
username: userData?.me?.username,
},
};
const newCacheComment = cache.writeFragment({
data: newComment,
fragment: gql`
fragment BSName on Comment {
id
createdAt
isMine
payload
user {
username
avatar
}
}
`,
});
cache.modify({
id: `Photo:${route?.params?.photoId}`,
fields: {
comments(prev) {
return [...prev, newCacheComment];
},
commentNumber(prev) {
return prev + 1;
},
},
});
}
};
const [createCommentMutation] = useMutation(CREATE_COMMENT_MUTATION, {
update: createCommentUpdate,
});
const onValid = async ({ comments }) => {
await createCommentMutation({
variables: {
photoId: route?.params?.photoId,
payload: comments,
},
});
await refetch();
console.log(updatePhoto);
};

Vue.js updating text in a modal

I have a modal and I am trying to dynamically update the text.
in my data
return {
count: {
value: 5
},
}
then I have a method
bulkUserImport: function() {
this.isLoading = true;
let _this = this;
axios.post('bulkUpdate', {'csv': this.importData})
.then((r) => console.log(r))
.then(() => this.isLoading = false)
.then(function() {
_this.$modal.show('dialog', {
title: 'Adding your new Clients',
text: `Jobscan is now provisioning your accounts, page will refresh in ${_this.count.value} seconds.`,
buttons: [
{
default: true,
handler: () => _this.$emit('close'),
}
]
});
_this.test()
})
.then(() => this.reloadClients());
},
Then the test method
test: function(){
if(this.count.value > 0){
this.count.value = this.count.value - 1;
console.log(this.count.value);
let temp = this;
setTimeout(function(count){
temp.test();
}, 1000);
}
},
In the text in the modal I have a variable _this.count.value that prints out 5. Then I have a call to _this.test() to update the variable.
In test(). I console.log the results and the number does go down
However, it is not updating the _this.count.value in the text. What am I doing wrong?
Here is the modal

How to check if JSON data is loaded

I use axios to fetch my JSON file en vuex for using the fetched data over multiple components.
The thing is that my page renders before all data is loaded.
The following works because I delayed the rendering by 2 seconds, without this timeout it would result in an error.
I would like to do this the proper way but am not sure how to do it.
STORE.JS
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
poss: null
},
getters: {
NAME: state => {
return state.name
},
POSS: state => {
return state.poss
}
},
mutations: {
SET_POSS : (state,payload) => {
state.poss = payload
},
ADD_POSS : (state,payload) => {
state.poss.push(payload)
},
},
actions:{
GET_POSS : async (context,payload) => {
let { data } = await axios.get("json/poss.json")
context.commit('SET_POSS',data)
},
SAVE_POSS : async (context,payload) => {
let { data } = await axios.post("json/poss.json")
context.commit('ADD_POSS',payload)
}
}
});
COMPONENT.VUE
module.exports = {
mounted:function(){
var self = this;
setTimeout(function () {
self.mkPageload()
}, 2000);
},
methods: {
mkPageload: function(){
let positions = this.$store.getters.POSS.pos
Object.keys(positions).forEach(key => {
// rendering
}
}
}
}
The desired result is that the page is only rendered after all data from the JSON file has been loaded.
There are several ways to solve this.
You could use wait / async in your component.
async mounted () {
await userStore.getAll()
// access getter and render
},
Your could watch vuex variable like (could be done without async but I like to add them)
async mounted () {
await userStore.getAll()
},
computed: {
...mapGetters('users')
},
watch: {
users(newValue, oldValue) {
....
// render
}
}
dont'forget to import the mapGetters: https://vuex.vuejs.org/guide/getters.html

How to stop the video if the slide has changed?

I need to stop the video when the slide is changed. The current code reacts to changing the variable, but does not stop the video. I use Clappr ^0.3.3, Vue-cli ^3.5.0 and Swiper ^4.5.0.
I change the boolean value to use it for the trigger in the player:
data: () => ({
slider_is_move: false,
}),
After request:
.then(() => {
// init slider
new Swiper('.content__slider', {
// Note: I removed extra options
on: {
slideChange: function () {
this.slider_is_move = true; // if slide is change
setTimeout(() => {
this.slider_is_move = false; // set the previous value
}, 1500);
}
}
});
// init clappr (video player)
if ( document.querySelector('.content-video') ) {
for (let i = 0; i < this.project_videos.length; i++) {
new Clappr.Player({
source: '/storage/' + this.project_videos[i],
parentId: '#container_' + (this.project_images.length + i),
mute: true,
width: document.querySelector('.content-item').offsetWidth,
height: document.querySelector('.content-item').offsetHeight,
events: {
onPlay: () => {
setInterval(() => {
if (this.slider_is_move === true) {
this.pause();
}
}, 1000);
}
}
});
}
}
});
If I add a console.log(), the code will work as it should, but it will not stop the video.
onPlay: () => {
setInterval(() => {
if (this.slider_is_move === true) {
this.pause();
}
}, 1000);
}
To make the video stop when you change the slide, you need to add a few lines in the code:
add name to object
let player_video = new Clappr.Player...
and pause it
player_video.pause();
You should watch the data attribute slider_is_move, and react to any changes in the state.
watch: {
slider_is_move: {
handler(nowMoving) {
if (nowMoving) {
this.pause();
}
},
}
}

VueJS - vue-charts.js

I am trying to pass data I fetch from API to vue-chartjs as props, I am doing as in the documentation but it does not work.
Main component
<monthly-price-chart :chartdata="chartdata"/>
import MonthlyPriceChart from './charts/MonthlyPriceChart'
export default {
data(){
return {
chartdata: {
labels: [],
datasets: [
{
label: 'Total price',
data: []
}
]
},
options: {
responsive: true,
maintainAspectRatio: false
}
}
},
components: {
MonthlyPriceChart
},
created() {
axios.get('/api/stats/monthly')
.then(response => {
let rides = response.data
forEach(rides, (ride) => {
this.chartdata.labels.push(ride.month)
this.chartdata.datasets[0].data.push(ride.total_price)
})
})
.catch(error => {
console.log(error)
})
}
}
In response I have an array of obejcts, each of which looks like this:
{
month: "2018-10",
total_distance: 40,
total_price: 119.95
}
Then I want to send the data somehow to the chart so I push the months to chartdata.labels and total_price to chartdata.datasets[0].data.
chart component
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
props: {
chartdata: {
type: Array | Object,
required: false
}
},
mounted () {
console.log(this.chartdata)
this.renderChart(this.chartdata, this.options)
}
}
console.log(this.chartdata) outputs my chartsdata object from my main component and the data is there so the data is passed correctly to chart but nothing is rendered on the chart.
The documentation says this:
<script>
import LineChart from './LineChart.vue'
export default {
name: 'LineChartContainer',
components: { LineChart },
data: () => ({
loaded: false,
chartdata: null
}),
async mounted () {
this.loaded = false
try {
const { userlist } = await fetch('/api/userlist')
this.chartData = userlist
this.loaded = true
} catch (e) {
console.error(e)
}
}
}
</script>
I find this documentation a bit vague because it does not explain what I need to pass in chartdatato the chart as props. Can you help me?
Your issue is that API requests are async. So it happens that your chart will be rendered, before your API request finishes. A common pattern is to use a loading state and v-if.
There is an example in the docs: https://vue-chartjs.org/guide/#chart-with-api-data