this time its something general and simple so i have not really code to provide.
The general steps are:
Pass an array as a prop to a child component
Inside the child component loop over the array with v-for
now i call an axios post method to modify the "user-list" (the user list is the array)
vue should now update this array but it doesnt because a prop is not reactive.
The Main question is: How do i use computed properties as passed down props to have the array live updated?
here is some code though:
<div class="users" v-for="participant in part" :key="participant.id">
<template v-if="participant.name !== username">
{{participant.name}}
<span>
<a style="cursor:pointer" title="kick" #click="kickUser(participant)">
...
props: ["participants", "username", "channel"],
methods: {
kickUser(user) {
axios
.post("/kickuser", { user: user, channel: this.channel })
// .then((this.participants = []));
}
the kickuser axios post method removes a user from the db so the array is reduced by the user kicked
hope you can help me with the computed properties
Making some assumptions here so I'll probably need to edit this as information comes to light...
You have a parent component with data. For example
data: () => ({ participants: [...] }),
You then pass that data to a child component
<Child :participants="participants"
:username="..." :channel="..."/>
and within that child component, you perform an action that involves making an HTTP request.
What you do then is emit an event from the child component
methods: {
async kickUser (user) {
let { data } = await axios.post('/kickuser', { user, channel: this.channel })
this.$emit('kick', data)
}
}
and listen for this event in the parent
<Child :participants="participants" #kick="handleKick"
:username="..." :channel="..."/>
// parent "methods"
methods: {
handleKick (data) {
this.participants = [] // or whatever you need to do
}
}
This process is outlined in Vue's documentation ~ One-Way Data Flow
Related
Can anyone please explain me what is happened in these codes and how can I solve it?
I get the data in the parent's mounted function and update its data. So I have the new object in the child. But the value of the property of this object is empty!
Parent:
<template>
<div class="main-page">
<main-content v-bind:config="mainContentConfig" />
</div>
</template>
mounted(){
fetchData().then(editions => { editions.sort((e1, e2) => e1.name.toLowerCase().localeCompare(e2.name.toLowerCase()))
this.mainContentConfig.intranetEditions = [...editions];
this.mainContentConfig.currentMenuIndex = 1;
});
}
Child:
mounted(){
console.log("AA==============>", this.config);
console.log("BB==============>", this.config.intranetEditions);
}
But on the console I have:
I found this problem when I fill other data in the child class with this.config.intranetEditions array which always is empty!
Edit:
I tried this code too, but no difference!
[...this.config.intranetEditions]
Edit 2 This code tested too, but nothing!
console.log("AA==============>", this.config);
console.log("BB==============>", JSON.stringify(this.config.intranetEditions));
The child-component is mounted but the parent fetch is not finished yet, so this.config is an observer until the fetch is done (so the then is fired) and the var fulfilled.
Can you try to watch the prop config in the child-component? then you will see when this.config is fulfilled.
https://v2.vuejs.org/v2/guide/computed.html#Watchers
UPDATE WITH EXAMPLE:
child-component
watch: {
config(newValue) {
console.log("AA==============>", newValue.intranetEditions);
checkConfigValue();
},
},
methods: {
checkConfigValue() {
console.log("BB==============>", this.config.intranetEditions);
};
},
So you can wether do something in the watcher with the newValue, or trigger a method and use this.config. Both consoles, will print the same in this case.
This is the method I'm using, pretty simple.
DailyCountTest: function (){
this.$store.dispatch("DailyCountAction")
let NewPatientTest = this.$store.getters.NewPatientCountGET
console.log(NewPatientTest)
}
The getter gets that data from a simple action that calls a django backend API.
I'm attempting to do some charting with the data so I need to assign them to variables. The only problem is I can't access the variables.
This is what the console looks like
And this is what it looks like expanded.
You can see the contents, but I also see empty brackets. Would anyone know how I could access those values? I've tried a bunch of map.(Object) examples and couldn't get any success with them.
Would anyone have any recommendation on how I can manipulate this array to get the contents?
Thanks!
Here is the Vuex path for the API data
Action:
DailyCountAction ({ commit }) {
axios({
method: "get",
url: "http://127.0.0.1:8000/MonthlyCountByDay/",
auth: {
username: "test",
password: "test"
}
}).then(response => {
commit('DailyCountMutation', response.data)
})
},
Mutation:
DailyCountMutation(state, DailyCount) {
const NewPatientMap = new Map(Object.entries(DailyCount));
NewPatientMap.forEach((value, key) => {
var NewPatientCycle = value['Current_Cycle_Date']
state.DailyCount.push(NewPatientCycle)
});
}
Getter:
NewPatientCountGET : state => {
return state.DailyCount
}
State:
DailyCount: []
This particular description of your problem caught my eye:
The getter gets that data from a simple action that calls a django backend API
That, to me, implies an asynchronous action and you might be getting a race condition. Would you be able to post a sample of your getter function to confirm my suspicion?
If that getter does indeed rely on an action to populate its contents, perhaps something to the effect of the following might do?
DailyCountTest: async () => {
await this.$store.dispatch('DailyCountAction')
await this.$store.dispatch('ActionThatPopulatesNewPatientCount')
let NewPatientTest = this.$store.getters.NewPatientCountGET
// ... do whatever with resulting array
}
You can also try with a computer property. You can import mapGetters
import { mapGetters } from 'vuex'
and later in computed properties:
computed: {
...mapGetters(['NewPatientCountGET'])
}
then you can use your NewPatientCountGET and it will update whenever the value changes in the store. (for example when the api returns a new value)
Hope that makes sense
Currently, I have a modal material dialog window that asks the user to input a number and then hit search. On search, it fetches data from api call and gets back a response object. I want to use the response object to populate a new page (edit form).
My question is, how can I past the data, particularly the number the user entered on the material dialog component to another component, so that it can fetch the api call results or how can I pass my response object to my edit from from dialog?
E.g.
Here's my search function:
search(searchNumber) {
if (this.selectedOption === 'Bill Number') {
this._transactionService.findExistingTransactionByBillNumber('U001', searchNumber)
.subscribe(data => this.transactionResponse = data);
console.log(JSON.stringify(this.transactionResponse));
this.router.navigate(['/edit-transaction-portal']);
} else {
this._transactionService.findExistingTransactionByTransactionNumber('U001', searchNumber)
.subscribe(data => this.transactionResponse = data);
console.log(JSON.stringify(this.transactionResponse));
this.router.navigate(['/edit-transaction-portal']);
}
}
I want to be able to either 1) pass the response object I get here or pass the searchNumber the user entered, so that I can do a lookup within my edit form component. I need to pass in either one from this component to my new component that I navigate to.
EDIT: Accepted solution shows how to add query params to this.router.navigate() and how to retrieve it by subscribing to activateRoute, a different approach than the one identified in the other SO post.
You can pass the number (bill/transaction)
this.router.navigate(['/edit-transaction-portal'], { queryParams: { bill: 'U001' } });
this.router.navigate(['/edit-transaction-portal'], { queryParams: { transaction: 'U001' } });
then in your component(edit-transaction-portal) hit the api to get the data. In component you should include ActivatedRoute in constructor. It will be something like:
isBill: boolean;
isTransaction: boolean;
number: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.sub = this.route
.queryParams
.subscribe(params => {
this.isBill = params['bill'] != undefined;
this.isTransaction = params['transaction'] != undefined;
this.number = this.isBill ? params['bill'] : params['transaction'];
// Call API here
});
}
My question is, how can I past the data, particularly the number the
user entered on the material dialog component to another component
You can pass it throw material dialog component. Inject dialogRef to you component which opened in the dialog:
constructor(
public dialogRef: MatDialogRef<SomeComponent>,
#Inject(MAT_DIALOG_DATA) public data: any,
) { }
After the submitting data, you can pass any data to component which opened this dialog, by closing the dialog:
onSubmit() {
this.service.postProduct(this.contract, this.product)
.subscribe(resp => {
this.dialogRef.close(resp);
});
}
And in your Parent component, who opened this dialog can get this passed data by subscribing to afterClosed() observable:
Parent.component.ts:
openDialog(id) {
const dialogRef = this.dialog.open(SomeComponent, {
data: { id: anyData}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
// do something...
}
});
}
Would I pass the data object in dialog.open()? How would I retrieve it
from there?
Look at openDialog() above. It has data property, that you can send to dialog components. And in the opened component inject MAT_DIALOG_DATA as this:
#Inject(MAT_DIALOG_DATA) public data: any,
to access passed data object as shown code above
Official docs[sharing-data-with-the-dialog-component]
if you want to pass data which the help of routing you have to define route which takes value as part of rout like as below
const appRoutes: Routes = [
{ path: 'hero/:id', component: HeroDetailComponent },];
it will from code side
gotoHeroes(hero: Hero) {
let heroId = hero ? hero.id : null;
// Pass along the hero id if available
// so that the HeroList component can select that hero.
// Include a junk 'foo' property for fun.
this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }]);
}
Read : https://angular.io/guide/router#router-imports
If you want to pass data between two component then there is #Input and #Output property concept in angular which allows you to pass data between components.
#Input() - this type of property allows you to pass data from parent to child component.
Output() - this type of property allows you to pass data from child to parent component.
Other way to do it is make use of Service as use the same instance of service between component.
Read : 3 ways to communicate between Angular components
I'm somewhat new to React, and using the re-base library to work with Firebase.
I'm currently trying to render a table, but because of the way my data is structured in firebase, I need to get a list of keys from two locations- the first one being a list of user keys that are a member of a team, and the second being the full user information.
The team node is structured like this: /teams/team_id/userkeys, and the user info is stored like this: /Users/userkey/{email, name, etc.}
My table consists of two react components: a table component and a row component.
My table component has props teamid passed to it, and I'm using re-base's bindToState functionality to get the associated user keys in componentWillMount(). Then, I use bindToState again to get the full user node, like so:
componentWillMount() {
this.ref = base.bindToState(`/teams/${this.props.data}/members`, {
context: this,
state: 'members',
asArray: true,
then() {
this.secondref = base.bindToState('/Users', {
context: this,
state: 'users',
asArray: true,
then() {
let membersKeys = this.state.members.map(function(item) {
return item.key;
});
let usersKeys = this.state.members.map(function(item) {
return item.key;
});
let onlyCorrectMembersKeys = intersection(membersKeys, usersKeys);
this.setState({
loading: false
});
}
});
}
});
}
As you can see, I create membersKeys and usersKeys and then use underscore.js's intersection function to get all the member keys that are in my users node (note: I do this because there are some cases where a user will be a member of a team, but not be under /Users).
The part I'm struggling with is adding an additional rebase call to create the full members array (ie. the user data from /Users for the keys in onlyCorrectMembersKeys.
Edit: I've tried
let allKeys = [];
onlyCorrectMembersKeys.forEach(function(element) {
base.fetch(`/Users/${element}`, {
asArray: true,
then(data) {
allKeys.prototype.concat(data);
}
});
});
But I'm receiving the error Error: REBASE: The options argument must contain a context property of type object. Instead, got undefined
I'm assuming that's because onlyCorrectMembersKeys hasn't been fully computed yet, but I'm struggling with how to figure out the best way to solve this..
For anyone dealing with this issue as well, I seemed to have found (somewhat) of a solution:
onlyCorrectMembersKeys.map(function(item) {
base.fetch(`/Users/${item}`, {
context: this,
asObject: true,
then(data) {
if (data) {
allKeyss.push({item,data});
this.setState({allKeys: allKeyss});
}
this.setState({loading: false});
},
onFailure(err) {
console.log(err);
this.setState({loading: false});
}
})
}, this);
}
This works fine, but when users and members state is updated, it doesn't update the allkeys state. I'm sure this is just due to my level of react knowledge, so when I figure that out I'll post the solution.
Edit: using listenTo instead of bindToState is the correct approach as bindToState's callback is only fired once.
I'm using firebase as my backend.
Inside of a data.service.ts, I create a Subject array which will be filled by the firebase observer on app init:
private orders = new Subject<any>();
orders$ = this.orders.asObservable();
firebase.database().ref(this.fbDataPath).on('child_added', (childSnapshot) => {
this.orders.next(
{
key: childSnapshot.key,
name: childSnapshot.val().name,
items: childSnapshot.val().items
}
)
})
I then provide a separate directory component with DataService and subscribe to its orders observable:
DataService.orders$.subscribe(
order => {
console.log('subscribe hit')
})
I can't seem to get the listener component to trigger on a next. I made this work for a boolean isLoggedIn, and I must be missing something in this scenario. Thanks!
It might be because you're using this in a closure. Remove the this from this.orders.next()