oi, this one seems so simple but it's giving me a headache.
I have a child component with a property passed down:
<dialog-child requests='requests'/>
the passed prop, is an object obtaining varied booleans. The dialog is v-modeled to in this case,
<dialog v-model='request.deleteItem'>
requests { deleteItem: false, editItem: false, syncItem: false, }
When I click on the delete button, I want to make a request to delete an item, and pull up this dialog component. This works fine if i simply change the bool in the object to true, but I need more control by passing the #click to a method and passing a parameter.
<btn #click='makeRequest(deleteItem)'>Activate Dialog</btn>
so in the method, I need to figure out how to say that the passed deleteItem, is request.deleteItem and then I would make it true.
makeRequest(requested){
//somewhow say
this.requests.requested = true
}
How could I pass in the parameter to take control of the objects property?
I could do a long form of multiple if checks, if requested = '' then make this prop true, but that feels gross.
I also need to pass in a second param, item after I figure this out - so to pass in two params do i just say methodName(param1, param2) and on click method(item1, item2) or do I need to create an object like method({item1, item2})?
To have everything nice and neat :) but:
For that we need option "to emit event on child component" but Vue.js does not work like that. So try this:
<template>
<div>
<dialog-child requests='requests' #resetRequest="resetRequest()"/>
<btn #click='makeRequest("deleteItem")'>Delete</btn>
</div>
</template>
<script>
import DialogChild from 'Dialog.vue'
export default {
components: { "dialog-child" : DialogChild },
data() {
return {
requests: {
makeRequest: false, //New Field
deleteItem: false,
editItem: false,
syncItem: false
}
}
},
methods: {
makeRequest(action) {
//So here you can create new request Object with whatever you want. Use action argument to check what you want to do here...
let newRequests = {
makeRequest: true,
deleteItem: true,
editItem: false,
syncItem: false
}
//Then this newRequest object need to copy to this.requests, this will update request object reference, and trigger "watch" in child component
this.requests = newRequests;
},
resetRequest() {
//Request object is again updated with new reference, but makeRequest is false so it will not trigger action in Dialog Child component
this.requests = {
makeRequest: false, //Now this is false,
deleteItem: false,
editItem: false,
syncItem: false
}
}
}
}
</script>
//And child component should be like this
<template>
<div>
</div>
</template>
<script>
export default {
props: {
requests: { Type: Object }
},
watch: {
requests(newVal) {
if(newVal && newVal.makeRequest) {
this.doStuff()
}
}
},
methods: {
doStuff() {
//So after doing what you want, you need to make event to reset requests
this.$emit('resetRequests');
}
}
}
</script>
i fixed this by changing the param to a string, and removing the request for a second item. Onwards to a item pass in too.
Related
Im trying to fix this error where i cant close the dialog by clicking the X button on the top right, but i can close it by clicking the "Agregar" or "Cancelar" button.
This is how i sync my Dialog
<el-dialog title="Agregar Persona" :visible.sync="getAgregarPersonaDialog">
And here is my Computed Property
computed: {
getAgregarPersonaDialog() {
return this.$store.state.agregarPersonaDialog;
}
}
This is how i change the value of my state
setAgregarPersonaDialogo(state) {
state.agregarPersonaDialog = !state.agregarPersonaDialog
},
And in my state i have this atribute
export default new Vuex.Store({
state: {
agregarPersonaDialog: false
}
});
This is the error i have everytime i click the X button on the dialog
Computed property "getAgregarPersonaDialog" was assigned to but it has no setter.
When using Vuex, if your need to mutate any data on state arises then you absolutely need an action that calls a mutation to mutate state.
This is the most important use case of Vuex, to keep track of actions that mutates state
what you did is absolutely wrong.
To achieve your goal, you need two things.
an action
a mutation
action: {
// The first parameter is an object, so it be destructured
// for simple access
doSomething({ commit }, payload){
// commit a change by calling mutation, second parameter
// is the arguments you passed to your action
commit('mutateData', payload)
}
},
mutations: {
mutateData(state, payload) {
// You can instead commit the argument
// I.e state.data = payload
state.agregarPersonaDialog = !state.agregarPersonaDialog;
}
},
You can then dispatch your actions in any components
methods: {
changeValue(){
this.$store.dispatch('doSomething', 'this is an arg');
// Note I passed an argument just for illustration
// in your case, you don't have to
}
}
Now your code should work
ti change the state you need
1. action
2. Mutator
example in store.js
state: {
agregarPersonaDialog: false,
},
// value is data what you send from your componet
action: {
changeState(context){
context.commit('changeValue')
},
mutations: {
changeValue(state) {
state.agregarPersonaDialog = !state.agregarPersonaDialog;
}
},
---------------------
in your compoent create method
methods: {
changeValue(){
this.$store.dispatch('changeState');
}
}
try this!
I have a couple of options in a <select> element. How can I call a function when I choose an option?
Here is what I have so far in terms of the JS:
export default {
name: 'Dropdown',
methods: {
onChange() {
logout();
},
},
computed: {
logout() {
console.log('logout);
},
},
};
My select menu looks like this: <select #change="onChange">...
When I select an option, I receive the following error: logout is not defined. Any ideas?
you need to use this to reference the instance, so it will be this.logout();
EDIT:
You need to create an onLogout in the methods property if you want to do something particular, a computed property is a reactive property that return something, it isn't really meant to do something that handle the logout.
As i see your logout computed property would be more about getting the current status of the user if he's logout or not, but it would be better to rename it.
So if you want to do something particular when the select change(like a logout method)
you need to adapt your component this way:
export default {
name: 'Dropdown',
methods: {
onChange() {
this.logout();
},
logout() {
console.log('logout called');
},
},
computed: {
userStatus() {
// return a state or something, but must return something
return ...
},
},
};
I invite you to read this documentation to have better idea about computed property and methods
https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties
https://v1.vuejs.org/guide/events.html
The logout function should be on the methods object top and you reference it using this.logout()
The button text 'completed' should persist after browser refresh based on whether var item is true (after button click). I am not sure what the issue is but I have tried Chrome as well so I don't think it is browser related.
<template>
<button type="button" v-bind:class="order_button_style" #click="on_order_button_click()">
{{ buttonText }}
</button>
</div>
</template>
<script>
export default {
item: '',
data() {
return {
item2: this.item
}
},
methods: {
on_order_button_click() {
this.item2 = true;
localStorage.setItem(this.item2);
}
},
mounted() {
const storedState = localStorage.getItem(this.item2) === 'false';
if (storedState) {
this.item2 = storedState;
}
},
computed: {
buttonText() {
return this.item2 === true ? "Completed" : "Complete";
},
order_button_style() {
return this.item2 === true
? "btn btn-danger"
: "btn btn-primary";
}
}
};
</script>
localStorage.setItem takes 2 params, name and value.
I believe you meant to write the following:
Setting an item in localStorage
localStorage.setItem('item', this.item2)
and retrieving it
localStorage.getItem('item')
A few comments on other parts of your code:
this.item2 === true can be shortened to this.item2 if item2 can never be anything other than a boolean.
You're currently only using the value from localStorage if it's false, which it will never be because you're only ever calling setItem with a value of true
I'm not sure what you're trying to do with the item prop in the top level of the object
Strongly consider using camelCase for your method names. Follow global conventions
UPDATE:
I think this is what you're trying to achieve:
on_order_button_click() { // Should probably rename this to `onOrderButtonClick`, the current method name hurts to look at
this.clickedOrderButton = true;
localStorage.setItem('clickedOrderButton', this.clickedOrderButton);
}
created() {
this.clickedOrderButton = localStorage.getItem('clickedOrderButton') === "true";
}
I've renamed item2 to clickedOrderButton. I have no idea why you'd name that variable item2 based on the code that is shown.
There's also no need to check whether clickedOrderButton is true before assigning it to clickedOrderButton, as it will resolve to false if it's not present (or intentionally set to something other than true) in localStorage.
Lastly, I've replaced mounted by created. As you're not accessing any DOM elements, there's no need to wait until the component is mounted to run that code
UPDATE#2:
If you have several instances of this component, you'll need to set use a different name than clickedOrderButton. You can use a unique identifier per button, which you can pass as a prop from above.
E.g.
props: {
id: { type: String, required: true }
}
...
localStorage.setItem(`clickedOrderButton-${this.id}`, this.clickedOrderButton);
...
localStorage.getItem(`clickedOrderButton-${this.id}`);
I have a Vue component called aui-button that is used like:
<aui-button classes="btn-primary test-class" :callback="test">Test Button</aui-button>
I'm trying to design the component to be able to run any given callback without the callback requiring any structural changes or special return values; basically, I want to just give it some code, and have it run it. I pass the callback as a prop and call it. Easy.
props: ['classes', 'callback'],
methods: {
runCallback() {
this.callback();
}
}
What I'm stuck on is how to change the state data of the button based on the callback given those constraints.
data: function() {
return {
loading: false
}
},
How can I change the value of a specific data value on the component after callback execution given that I'd like to have zero say over what the callback argument is doing? Ideally these have a wide array of uses, from API calls to simple value changes.
Here's another answer in response to your comment. If you really wanted to implement it that way then there's nothing stopping you.
The problem is that the callback will be asynchronous (otherwise, what's the point of setting a loading state), so the component needs to be told when the asynchronous callback has completed.
You could define your callback functions so that they take a done() callback.
AuiButton.vue
props: ['classes', 'callback'],
data() { return { loading: false}},
methods: {
runCallback() {
this.loading = true;
this.callback(this.doneCallback);
},
doneCallback() {
this.loading = false;
},
},
Parent Component
<aui-button classes="btn-primary test-class" :callback="test">Test Button</aui-button>
...
methods: {
test(doneCallback) {
doSometingAsync(someData, (error, result) => {
doneCallback();
// do something with result..
})
},
Perhaps a better solution is to use events, but give the click event a done callback:
AuiButton.vue
props: ['classes'], // don't need to pass the callback as a prop anymore.
data() { return { loading: false}},
methods: {
runCallback() {
this.loading = true;
this.$emit('click', this.doneCallback);
},
doneCallback() {
this.loading = false;
},
},
Parent Component
<aui-button classes="btn-primary test-class" #click="test">Test Button</aui-button>
...
methods: {
test(doneCallback) {
doSometingAsync(someData, (error, result) => {
doneCallback();
// do something with result..
})
},
Rather than pass a callback to your button component, it is recommended practice to make your component $emit an event to the parent. The parent can then run whatever code it wants in the event handler.
Then, you should pass a loading prop to your component to control its loading state. e.g:
AuiButton.vue
<button :classes="classes" :disabled="loading" #click="$emit('click') ...>
...
props: {
classes: String,
loading: {
type: Boolean,
default: false
},
Parent component
<aui-button classes="btn-primary test-class" :loading="loading" #click="buttonClick">
Test Button
</aui-button>
...
data() { return {
loading: false,
} },
methods: {
buttonClick() {
this.loading = true;
doSometingAsync(someData, (error, result) => {
this.loading = false;
// do something with result..
})
},
Now your button component doesn't need to do anything clever - it's told whether it should be in the loading state and it tells its parent whenever it is clicked.
Service.ts:
I have create an object in my service.ts file, Now I want to update object values using BehaviorSubject, so I can use this updated object in my different components
private _menuUpdate = {
bankFlag: false,
contactsFlag: false,
educationDataFlag: false,
examFlag: false,
existingRelationShipFlag: false,
nomineeFlag: false,
personalFlag: false,
supportDocsFalg: false,
workExpFlag: false
}
public menuDisableStatus = new BehaviorSubject<Object>(this._menuUpdate);
menuStatus = this.menuDisableStatus.asObservable();
changeStatus(statusObj) {
this.menuDisableStatus.next(statusObj);
}
Now in my components1.ts Example
click(){
this.menuDisableStatus.educationDataFlag = true;
this.mliService.changeStatus(this.menuDisableStatus.educationDataFlag);
}
Now in my components2.ts Example
this.mliService.menuStatus.subscribe((data) => {
this.menuDisableStatus = data;
});
console.log(this.menuDisableStatus);
Here console give me 'true' instead of Update object.
In your component1 you call changeStatus (and in result the "next" of the observable) not to the primary subject but to a property of this subject.
Change it to this.mliService.changeStatus(this.menuDisableStatus); and it should work