The $store i is not defined on the instance but referenced during render in vue, why? - vue.js

I need to create an instance and then return it as $el. nodeTemplate is a function in mounted hook. But i have an error that in VisualComponent $store is not defined on the instance but referenced during render.
import router from "../../router";
import store from "../../store";
...
const nodeTemplate = (n, parent, cyn) => {
// parent is the same as window
const Card = Vue.use(store).use(router).extend(Visual);
const instance = new Card({
propsData: {
vis: n.graphData ? n.graphData : {},
visualType: n.visualType ? n.visualType : {},
size: '',
className: cyn.classes(),
},
});
instance.$mount();
return instance.$el;
};
...
cy1.nodeHtmlLabel([
{
query: 'node',
tpl: function (n) {
n.el = nodeTemplate(n, parent, cy1.$(`#${n.id}`));
return n.el
}
}
])

Related

Nuxt.js store - update object in store object - throw Error: [vuex] do not mutate vuex store state outside mutation handlers

in my Nuxt.js app
my store object is:
export const state = () => ({
curEditRP: {
attributes:{
name:"",
spouse: {
type: "", // wife/husband
name: ""
}
}
})
to update the attributes of curEditRP i wrote mutations function that called setCurEditRPAttrState:
export const mutations = {
setCurEditRPAttrState(state, payload) {
state.curEditRP.attributes[payload.attr] = payload.value;
},
}
from template i used it:
this.$store.commit("setCurEditRPAttrState", {
value: value,
attr: attributeName,
});
In a name update it works great
But in a spouse update it throws an error
Error: [vuex] do not mutate vuex store state outside mutation handlers
examples of values:
name (works great):
this.$store.commit("setCurEditRPAttrState", {
value: "Peter",
attr: "name",
});
spouse (throws an error):
this.$store.commit("setCurEditRPAttrState", {
value: { type:"wife",name:"S" },
attr: "spouse",
});
clarification: value is v-model variable
Bs"d, I find the solution.
in update object or array of object i need itarate over object properties and update each one individually
setCurEditRPAttrState(state, payload) {
if(typeof(payload.value) == 'object') {
let stateAttribute = state.curEditRP.attributes[payload.attr];
if(Array.isArray(payload.value)) {
let stateArrLen = stateAttribute.length;
let valuelen = payload.value.length;
while(stateArrLen > valuelen) {
stateAttribute.pop();
stateArrLen --;
}
for (let index = 0; index < payload.value.length; index++) {
const element = payload.value[index];
if(stateAttribute.length < index + 1) stateAttribute.push({});
Object.keys(element).forEach( key => {
Vue.set(stateAttribute[index], key, element[key])
})
}
}
else {
Object.keys(payload.value).forEach( key => {
Vue.set(stateAttribute, key, payload.value[key])
})
}
}
else {
state.curEditRP.attributes[payload.attr] = payload.value;
}
},

Vuejs: listen to props changes and use it

I am developing a project using Vue JS and I need to watch the props changes and call it inside a <span>.
I have used watch() and it shows that the props values are assigned.
But when I call it inside the <span> the value is not showing.
props: ['verifyText', 'verifyValue', 'profileId', 'logged', 'verifyType', 'status'],
watch: {
verifyText: function () { // watch it
this.verify_text = this.verifyText;
},
verifyValue: function () {
this.verify_value = this.verifyValue;
},
verifyType: function () {
this.verify_type = this.verifyType;
}
},
data() {
return {
verify_type: this.verifyType,
verify_text: this.verifyText,
verify_value: this.verifyValue,
}
},
//using inside span
<span>{{verify_text}}</span>
Receive and insert new data that changes from 'watch'
Try this.
props: ['verifyText', 'verifyValue', 'profileId', 'logged', 'verifyType', 'status'],
watch: {
verifyText: function (new_value) {
this.verify_text = new_value;
}
},
data() {
return {
verify_text: this.verifyText,
}
},
//using inside span
<span>{{verify_text}}</span>
I solved this issue by watching the verify_text in the parent component.
'verify_text': function (value) {
this.verify_text = value;
},
Same for the verify_type and verify_value
Thank you all for replying.

fireEvent on SegmentedControlIOS

I am using react-native-testing-library - https://callstack.github.io/react-native-testing-library/docs/getting-started
I have a <SegmentedControlIOS> - https://facebook.github.io/react-native/docs/segmentedcontrolios
I want to pres the first segment. I am doing this:
const testID = "SegmentedControl";
const stub = jest.fn();
const values = [{ label: "foo" }];
const { getByTestId } = render(
<SegmentedControlIOS values={['foo', 'bar']} onChange={stub} testID={testID} />
);
expect(() => {
getByTestId(testID);
}).not.toThrow();
fireEvent(getByTestId(testID), "change ", {
nativeEvent: {
value: values[0],
selectedSegmentIndex: 0,
},
});
However I get the error:
No handler function found for event: "change "
Screenshot below. Anyone know how to press different segments in <SegmentedControlIOS>?
fireEvent(element: ReactTestInstance, eventName: string, ...data:
Array): void
The change function is located in the fireEvent object. Here's how to use it:
Version 5 or later:
fireEvent.change(getByTestId(testID), { target: { value: values[0],selectedSegmentIndex: 0 } });
Version 5 or before:
const input = getByTestId(testID);
input.value = values[0];
input.selectedSegmentIndex = 0;
fireEvent.change(input);
If you want to check the onChange function of SegmentedControlIOS,
using fireEvent with native events that aren't already aliased by the fireEvent api.
// you can omit the `on` prefix
fireEvent(getByTestId(testID), 'onChange');
A solution was posted here, I didn't try it yet, but it looks more right I think - https://github.com/callstack/react-native-testing-library/issues/220#issuecomment-541067962
import React from "react";
import { SegmentedControlIOS } from "react-native";
import { fireEvent, render } from "react-native-testing-library";
const testID = "SegmentedControl";
const stub = jest.fn();
const values = [{ label: "foo" }];
const { getByTestId } = render(
<SegmentedControlIOS
values={["foo", "bar"]}
onChange={stub}
testID={testID}
/>,
);
it("sends events", () => {
fireEvent(getByTestId(testID), "onChange", {
nativeEvent: {
value: values[0],
selectedSegmentIndex: 0,
},
});
});

How to dynamically render strings in Vue?

I am pulling an array on images from Netlify CMS and passing that to vue-picture-swipe component, but the acutal images don't render, even though the path is correct etc.
Not sure what I am doing wrong?
Template
vue-picture-swipe(:items="items")
Script
<script>
export default {
data: function() {
return {
items: []
};
},
created: function () {
this.imageList()
},
methods: {
imageList: function () {
const files = require.context('~/content/gallery/images/', false, /\.md$/);
let images = files.keys().map(key => ({
...files(key)
}));
let items = images.map(function(value) {
return {
'src': value.attributes.imgSrc,
'thumbnail': value.attributes.imgSrc,
'alt': value.attributes.imgDesc
}
});
return this.items = items
}
}
};
</script>
Rendered HTML
<img src="/assets/uploads/image.jpg" alt="Test Image description" itemprop="thumbnail">
According to your output, if value.attributes.imgSrc renders a relative path like src="/assets/uploads/image.jpg", try to require this path.
I'm assuming your "assets" and "components" folders are directly under "src":
let items = images.map(function(value) {
return {
'src': require('..' + value.attributes.imgSrc), // or require('#' + value.attributes.imgSrc)
'thumbnail': require('..' + value.attributes.imgSrc),
'alt': value.attributes.imgDesc
}
})
Note that vue-picture-swipe items props need w and h attributes for each item.

Crash with simple history push

just trying come silly stuff and playing around with Cycle.js. and running into problem. Basically I just have a button. When you click it it's suppose to navigate the location to a random hash and display it. Almost like a stupid router w/o predefined routes. Ie. routes are dynamic. Again this isn't anything practical I am just messing with some stuff and trying to learn Cycle.js. But the code below crashes after I click "Add" button. However the location is updated. If I actually just navigate to "#/asdf" it displays the correct content with "Hash: #/asdf". Not sure why the flow is crashing with error:
render-dom.js:242 TypeError: Cannot read property 'subscribe' of undefined(…)
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import ranomdstring from 'randomstring';
const history = createHashHistory({ queryKey: false });
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => {
return ranomdstring.generate(10);
}).startWith(null);
const vtree$ = create$.map(rs => rs ?
history.push(`/${rs}`) :
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$ };
}
function main(sources) {
const hash = location.hash;
const DOM = sources.DOM;
const vtree$ = hash ?
Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
) :
CreateButton({ DOM }).DOM;
return {
DOM: vtree$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container')
});
Thank you for the help
I would further suggest using #cycle/history to do your route changing
(Only showing relevant parts)
import {makeHistoryDriver} from '#cycle/history'
import {createHashHistory} from 'history'
function main(sources) {
...
return {history: Rx.Observable.just('/some/route') } // a stream of urls
}
const history = createHashHistory({ queryKey: false })
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
history: makeHistoryDriver(history),
})
On your function CreateButton you are mapping your clicks to history.push() instead of mapping it to a vtree which causes the error:
function CreateButton({ DOM }) {
...
const vtree$ = create$.map(rs => rs
? history.push(`/${rs}`) // <-- not a vtree
: button('.create-button .btn .btn-default', 'Add')
);
...
}
Instead you could use the do operator to perform the hashchange:
function CreateButton({ DOM }) {
const create$ =
...
.do(history.push(`/${rs}`)); // <-- here
const vtree$ = Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
...
}
However in functional programming you should not perform side effects on you app logic, every function must remain pure. Instead, all side effects should be handled by drivers. To learn more take a look at the drivers section on Cycle's documentation
To see a working driver jump at the end of the message.
Moreover on your main function you were not using streams to render your vtree. It would have not been reactive to locationHash changes because vtree$ = hash ? ... : ... is only evaluated once on app bootstrapping (when the main function is evaluated and "wires" every streams together).
An improvement will be to declare your main's vtree$ as following while keeping the same logic:
const vtree$ = hash$.map((hash) => hash ? ... : ...)
Here is a complete solution with a small locationHash driver:
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import randomstring from 'randomstring';
function makeLocationHashDriver (params) {
const history = createHashHistory(params);
return (routeChange$) => {
routeChange$
.filter(hash => {
const currentHash = location.hash.replace(/^#?\//g, '')
return hash && hash !== currentHash
})
.subscribe(hash => history.push(`/${hash}`));
return Rx.Observable.fromEvent(window, 'hashchange')
.startWith({})
.map(_ => location.hash);
}
}
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => randomstring.generate(10))
.startWith(null);
const vtree$ = Rx.Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$, routeChange$: create$ };
}
function main({ DOM, hash }) {
const button = CreateButton({ DOM })
const vtree$ = hash.map(hash => hash
? Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
)
: button.DOM
)
return {
DOM: vtree$,
hash: button.routeChange$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
hash: makeLocationHashDriver({ queryKey: false })
});
PS: there is a typo in your randomstring function name, I fixed it in my example.