How can I change state of the Grid.js component from the plugin context?
I'm trying to implement a visual configurator for the pagination.limit prop (https://gridjs.io/docs/config/pagination):
import { BaseComponent, BaseProps, h, PluginPosition } from 'gridjs';
class LimitConfigurator extends BaseComponent {
setLimit(limitNew) {
// this.setState({ pagination: {limit: limitNew}});
// this.config.pagination.limit = limitNew;
}
render() {
const self = this;
return h(
'div',
{ class: 'limit-configurator' },
[
h('span', { onclick: function () { self.setLimit(10); } }, '10'),
h('span', {}, '25'),
h('span', {}, '50'),
]
);
}
}
It renders something like 10 | 25 | 50 under the grid's footer and dynamically sets new per-page number for the pagination.limit path in the original component. Registration code:
// somewhere in the Vue component (using gridjs-vue bridge)...
async mounted() {
await elementReady('.grid-operator', { stopOnDomReady: false });
const gridComponent = this.$refs.gridReference.$data.grid;
gridComponent.plugin.add(
{
id: 'limitEditor',
component: LimitConfigurator,
position: PluginPosition.Footer,
},
);
gridComponent.forceRender();
},
I see prop values in the this.config but don't know how to properly manipulate them from the plugin (currently learning preact + vue environment). Is there a "convenient" way to do it?
I'm not sure if you've found a solution. But here is my take as I recently came across this and figured.
In a plugin which extends the base component, we have access to this.config. On this.config we have eventEmitter property. We can emit events and listen on the grid object which we originally created as gridjs has a global EventEmitter object.
Eg:
const grid = new Grid({
columns: ['Name', 'Email', 'Phone Number'],
sort: true,
search: true,
data: [
['John', 'john#example.com', '(353) 01 222 3333'],
['Mark', 'mark#gmail.com', '(01) 22 888 4444'],
['Eoin', 'eo3n#yahoo.com', '(05) 10 878 5554'],
['Nisen', 'nis900#gmail.com', '313 333 1923']
]
});
grid.on('custom-event', data => console.log(data));
From your plugin method, you can just emit the 'custom-event' like this.config.eventEmitter.emit('custom-event', 'foobar')
Related
I have a multi step form that basically has these basic steps: select services -> contact -> billing. I display a progress bar and emit events when the user changes the step they're on, and this is my current basic pattern with xstate:
const formMachine = new Machine({
id: 'form-machine',
initial: 'selectService',
context: {
progress: 0,
pathname: '/select-service',
},
states: {
selectService: {
entry: assign({
progress: 0,
pathname: '/select-service',
}),
on: {
NEXT: 'contact',
}
},
contact: {
entry: assign({
progress: 1 / 3,
pathname: '/billing'
}),
on: {
PREVIOUS: 'selectService',
NEXT: 'billing',
}
},
// ... there's more actions but that's the gist of it
}
});
Here's the visualization:
In my react component, I watch this service for changes in pathname so I can push to the history
function SignupFormWizard() {
const history = useHistory();
const [state, send, service] = useMachine(formMachine);
useEffect(() => {
const subscription = service.subscribe((state) => {
history.push(state.context.pathname);
});
return subscription.unsubscribe;
}, [service, history]);
// ...
}
However, here's the problem: whenever I revisit a route (say, I directly navigate to /billing), it will immediately bring me back to /select-service. This makes sense with my code because of the initial state, and the subscription, that it will do that.
How would I go about initializing the state machine at a specific node?
useMachine hook accepts second parameter which is a configuration object. In this object you can set state using state key, but you will have to construct state yourself, and it would look something like this:
let createdState = State.create(stateDefinition);
let resolvedState = formMachine.resolve(state);
let [state, send, service] = useMachine(formMachine, {state: resolvedState});
In my opinion it works well when you need to restore persisting state, but creating stateDefinition manually from scratch is just too much hustle.
What you can do, is create initial state and choose where you want to actually start:
initial: {
always: [
{
target: "selectService",
cond: "isSelectServicePage",
},
{
target: "contact",
cons: "isContactPage",
},
{
target: "billing",
cond: "isBillingPage",
},
],
}
Then, when you are starting your machine, all you have to do is set initial context value:
let location = useLocation();
let [state, send, service] = useMachine(formMachine, {
context: { pathname: location.pathname },
});
The other answer is almost correct, to be more precise, you can move to first state which will decide the next step dynamically, based on context assigned.
createMachine(
{
id: "Inspection Machine",
initial:
"decideIfNewOrExisting",
states: {
"decideIfNewOrExisting": {
always: [
{
target: "initialiseJob",
cond: "isNewJob"
},
{
target: "loadExistingJob"
}
]
},
...
I cannot assign the value of the calculated user data to the object in the data, but the data is lost when the page is refreshed.
import Vuetify from "vuetify"
import {
UserData
} from "../../store/userModule";
import jsonDict from "../../jsonFiles/data.json"
import jsonfile from "../../jsonFiles/jsonfile";
export default {
name: "userProfileUpdate",
data() {
return {
selected: "Choose Province",
rules: [
value => !!value || 'Bu alan boş bırakılamaz',
value => (value || '').length <= 20 || 'Max 20 characters',
value => {
const pattern = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return pattern.test(value) || 'Geçersiz e posta'
},
],
options: jsonDict.Gender,
options2: jsonDict.educational_status,
educational_status: '',
gender: '',
birthday: '',
email: '',
phone_number: '',
username: '',
first_name: '',
last_name: '',
profileData: {
}
}
},
created() {
this.$store.dispatch('initUserData')
this.$store.dispatch('inijson')
},
I have tried many ways it disappears when the page is refreshed even creating computed data but somehow it could not keep the data on the screen after the page refresh
computed: {
genderq() {
for (var i in this.$store.getters.user) {
return this.$store.getters.user[i]
}
return this.$store.getters.user
},
userdata() {
for (const i in this.$store.getters.getUser) {
var data = this.$store.getters.getUser[i]
this.username = data['username']
//this.$store.dispatch('getJsonData',data['gender'])
return data
}
return this.$store.getters.getUser
},
},
Hey you could try using localStorage or sessionStorage, and add the mounted() property to your component (this property is fired when the component is mounted) and then you could affect your data() values from the localStorage for example
data() => { myData: 0 },
computed()=>{
storeValue(){
localStorage.setItem('data', this.myData)
}
},
mounted() =>{
localStorage.getItem('data') ? this.myData = localStorage.getItem('data') : null //null because in data() myData has a default value but you can say this.myData = 0
}
With the mounted lifecycle property and the browser storage, you will have a trace of every value you want to keep between 2 refreshes (look for both localstorage and sessionStorage as they don't last the same time), basically, you can have a method (not a computed) that stores the object you want in the storage, then you can call this method at the end of every computed property that modifies the data you want to keep between refreshes.
edit: here is a link to help you to understand the lifecycle of a vue component it might help you later too if you want to create more complex components, lifecycle diagram
Best regards
I trying to return back sorted data (which is the already defined state) in a list with the help of a getter, then assign it to the html list in my vue, but it seems it's empty when I check with the vuex tools.
I don't know what am doing wrong.
Below is my store.js file
export default {
namespaced: true,
state:{
displayChatMessages: [],
},
mutations:{
create(state, payload) {
state.displayChatMessages.push(payload)
},
reset(state){
state.displayChatMessages = []
},
},
actions :{
getAllData:({commit}, payload) => {
commit('create',payload)
},
},
getters:{
filteredChatMessages: state => (chatID) => {
return state.displayChatMessages[0]
.filter(el => el.groupid === chatID).sort((l,r)=> l.timestamp - r.timestamp)
},
},
}
Then, after, I call it in the computed area like below :
...mapGetters('chatMessages',['filteredChatMessages']),
Then , I call the Getter inside my function , like below :
getFilteredMessages: function() {
let vm = this
return vm.filteredChatMessages(vm.groupID)
},
Then afterwards, then I set the getFilteredMessages() to the list , getFilteredMessages() , is also defined in the computed section.
But when I look into my vuex tools , I don't see it as an array :
What am I doing wrong ?
I am having an issue with my component data being updated. I have a component that is being used as a data object in another component's data field. The issue I am having is when I click on the submit button, the method should just take an input of firstname and lastname and update the child's search data field with it. However, it seems that while Vue is letting me push the data without errors, when I console.log afterwards I get an empty array. Can someone tell me what's going on that I am missing? Any help is much appreciated!
Here is the "child" component's (PatientSearch) code:
export default {
data: () => ({
search: [],
selected: [],
headers: [
{ text: 'Actions', value: '' },
{ text: 'Name', value: 'name' },
{ text: 'Status', value: 'status' },
],
items: [],
}),
created() {
//axios call that inserts retrieved data into items array
}
Here is the "parent" components code where child component is being used:
export default {
data: () => ({
PatientSearch,
...
}),
methods: {
submit: function() {
let searchString = this.firstname + ' ' + this.lastname;
console.log(searchString);
PatientSearch.data().search.push(searchString);
console.log('IN PARENT');
console.log(PatientSearch.data().search);
},
<template>
...
<app-layout title="Patient List" :children=PatientSearch>
</app-layout>
...
</template>
parent component should not access the child data.
you shuold pass your data from the parent to the child with props.
half of your work is done-
you do that very well in the parent side- you pass it the title and the children, but you forgot to accept the props in the child side. its very simple- you just add the props object to the child:
export default {
data: () => ({
search: [],
selected: [],
headers: [
{ text: 'Actions', value: '' },
{ text: 'Name', value: 'name' },
{ text: 'Status', value: 'status' },
],
items: [],
}),
props:{
title:{
type:string,
default:''
},
children:{
type:object,
default:()=>{},
}
},
created() {
//axios call that inserts retrieved data into items array
}
the props are available inside the child via this.propName.
to pass data from the child back to the parent, you can use a custom event.
you can also use a global store in your app, to manage data and open access to it in every component.
I've made my filters section using vue.js. I inject all the components through ajax and they response dynamically to those filters. Components in my case represent cars, they have price, marks, etc...
Now I'd like to add two more filters that allow me to sort them by some field (price, for instance). I've been reading and it's quite easy to sort lists specifying a field and a order...
How should I proceed to create that list and so, being able to sort it.
Here I made a little fiddle, very simple, in which I'd to sort the cars by prize once I click the filter.
var Car = Vue.extend({
template: '#template_box_car',
props: {
show: {
default: true
},
code: {
default: ""
},
prize: {
default: 0
},
description: {
default: "No comment"
}
}
});
//register component
Vue.component('box_car',Car);
//create a root instance
var vm = new Vue({
el: 'body',
methods: {
sortBy: function(field, order){
}
}
});
First, store the data for each car component in a data property in the parent component:
data: function () {
return {
cars: [
{ code: '11A', prize: 5.00, description: 'Ford Ka' },
{ code: '11B', prize: 3.00, description: 'Kia ceed' },
{ code: '11C', prize: 6.00, description: 'Ford Ka' },
{ code: '13A', prize: 45.00, description: 'Mercedes A' },
{ code: '17B', prize: 20.00, description: 'Seat Leon' },
]
}
},
Then, use the v-for directive to create a box_carcomponent for each of the objects in your cars data property:
// In your version of Vue.js it would look like this:
<box_car
v-for="car in cars"
:code="car.code"
:prize="car.prize"
:description="car.description"
:track-by="code"
></box_car>
// In newer versions of Vue.js, you can pass each object to the `v-bind` directive
// so you don't need to explicitly set each property:
<box_car v-for="car in cars" v-bind="car" :key="car.code"></box_car>
Then, in your sortBy method, simply sort the cars array:
// I used lodash, but you can sort it however you want:
methods: {
sortBy: function(field, order) {
this.cars = _.orderBy(this.cars, field, order);
}
}
Here's a working fiddle.