I have managed to retrieve data from Firebase, however, I am unable to store the data into a variable I have declared. I want to store in a variable is so that I am able to use at another method.
Please help.
These are the codes that I have tried.
1st method, rest api
retrieveUser(){
this.restProvider.retrieveUser(this.emailAdd, this.pw)
.subscribe(listUser => {
this.users = userList.results //trying to store to users variable
console.log(listUser);
},
err => {
console.log(err);
},
() => console.log('success')
);}
2nd method to use for some IF-ELSE
loginBtnPress(event){
this.retrieveUser();
console.log(this.users);
}
You are doing it wrong. this.users is getting updated using observables. So, if you try to retrieve its value before the value has been updated, you wont get it as expected. You can call it as below,
retrieveUser(){
this.restProvider.retrieveUser(this.emailAdd, this.pw)
.subscribe(listUser => {
this.users = userList.results //trying to store to users variable
callYourMethodWithUpdatedValue(this.users); // <-- Pass value here
},
err => {
console.log(err);
},
() => console.log('success')
);}
The callYourMethodWithUpdatedValue is called every time(and as soon as) the value this.users is updated
Update 1
You can't retrieve async value in one method and expect that value to be used in some other method on button click. Reason being, your are expecting value on that button click , but since its a async call (can take n secs), you can't be assured that the value will be populated when the value is used through some button call.
That's wrong implementation. You need to change the architecture to either of below:
Don't route to that page unless the user value has been resolved (received). Check canActivate and canActivateChildren.
Change the UX where you are trying to retrieve the use async variable on button click, and activate the button when the value has been received (Here you can use Subject ). Something like this demo
Related
I am using this json server in my Angular app, to create, fetch, and delete posts.
In the following method, I delete a post with a specified id:
deleteConsumer(post: Post): Observable<Post> {
const url = `${this.apiUrl}/${post.id}`;
return this.httpClient.delete<Post>(url);
}
I looked at the .delete code and searched for something like a .deleteall but could not find it. Is there really no such method that would delete everything?
If there really isn't, then my attempt at doing it myself is not paying off, because what I have done is not working:
deleteConsumers(): Observable<Post> {
let i: number = 0;
this.httpClient.get<Post[]>(this.apiUrl).forEach(
() => {
++i;
const url = `${this.apiUrl}/${i}`;
return this.httpClient.delete<Post>(url);
}
);
}
Obviously, this is wrong in terms of return type, but I cannot figure out what to do... How can I modify the first method, so it would go through all the json objects in my db.json file; meaning iterate through all the existing posts and delete them all?
I did encounter this when using json-server with Vue.js and I realized that there was no special function to delete all at once. I had to work around it.
So, for example in your case, I would first map the posts array to get a new array with only the post ids:
const postsIdsArray = this.posts.map((post) => post.id)
Then, assuming you already have a function to delete one post given the id, I would then execute the function for each of the ids in the array:
postsIdsArray.forEach((id) => this.deletePost(id))
Just combine the two lines in one JavaScript function (in this case I used Vue.js):
deleteAllPosts(){
const postsIdsArray = this.posts.map((post) => post.id)
postsIdsArray.forEach((id) => this.deletePost(id))
}
I am stuck on this problem from quiet sometime. I have created a table with 3 columns out of which the for two columns I can use prop property to display the contents of each row for those two columns. Now, for the third column, I want to display contents from another array, how do I display this information in the third column.
Please find the example of the code below:
This is the HTML Code
<el-table :data = "data_table">
<el-table-column
prop = "Id"
label= "Unique ID">
</el-table-column>
<el-table-column
prop = "color"
label = "Color">
</el-table-column>
<el-table-column
prop = ""
label = "Count">
<template slot-scope="scope">
<el-button type="text" #click="dialogVisible = true; get_total_count_users(scope.row)">{{users.length}}</el-button>
<!--Skipping the code for dialog box..I have tested that part pretty well, so I know it works. -->
</template>
</el-table-column>
</el-table>
This is the javascript part of the code:
<script>
export default {
data(){
return{
data_table:[], // I fill the data_table array using some AJAX/Axios calls which has props Id and Color.
users: [], // I fill the users array using some AJAX/Axios calls which has multiple user information.
};
},
methods:{
get_total_count_users(row){
// axios call, etc. This part works successfully, I checked the values.
}
}
</script>
A little explanation for the above code:
I make an AJAX/Axios call to an API which return me a list/array of value in data-table array. It had two props in it, that is Id and Color. I make another axios/AJX call to an api which returns me the list of the users based on the Id present on that row of the table. Each row will have a unique Id. Using that Id, I make an axios call to an api .. example, www.example/{{Id}}.com .This returns me a list of users linked to that id. Now, my next task is to display the total users (by taking the length of the users array) and displaying it as a button. But, as I am not using prop to display the values (length of users array for each row), the value in the button is displayed the same through all the rows. It keeps changing for the entire column if I click a button on any of the rows.
get_total_count_users(scope.row) function is used to make an axios/AJAX call to www.example/{{Id}}.com and stores multiple user information tied with that Id in users array.
Please refer to the image below:
Initially, all values are 0, as the Id in the first row has 0 users attached to it.
When I click on the 3rd rows button (which initially has 0 in it), all the values in that column change to 2, as the Id in the 3rd row has two users tied to it.
Hence, the issue here is that, I simply want to display total number of users (count) each row based on that id without using the prop property.
Hope the above explanation and example is helpful to understand the problem.
Any help would be appreciated.
The answer will solve the problem but is not a specific solution that is defined to get data from multiple arrays into your data table.
You can chain your axios responses and then use a foreach to add the variables to your object inside array.
So I am assuming that you are calling a method on mount like this:
data: () => ({ tableData: [] }),
mounted() {
this.getData();
}
now within your getData() function make different axios calls and put your response into the table, with something like this.
methods: {
getData() {
var myTableData = [];
axios({ method: 'GET', url: 'http://first-url', headers: [...] }).then(res => {
//we have got the table data here
myTableData = res.data;
//looping through data and making axios calls based on data.
myTableData.foreach((row, index) => {
var newUrl = 'https://getdatafrom.com/'+ row.id+'/'; //using the data from previous call.
axios({ method: 'GET', url: newUrl, headers: [...]}).then(res2 => {
var counts = res.data;
// adding variable myCount to the table data array.
row.myCount = counts[index];
}).catch(err => { console.error(err)})
})
// setting data object
this.tableData = myTableData;
}).catch(err => { console.error(err) })
}
}
let me know if you have any issue.
My node.js MySQL query returns a single row wrapped in [RowPacketData] which I can normally access the ID field using results[0].ID.
However, when I store the result in React state (using hooks) it does not work. I can access the result object, but not fields within it.
function MyReactComponent() {
const [dbEntry, setDbEntry] = useState();
useEffect(() => {
const fetchData = async () => {
const result = await queryFunc(`SELECT * FROM table LIMIT 1`);
console.log(result[0]); // <-- Works (shows [RowDataPacket] object)
console.log(result[0].ID); // <-- Works (shows ID)
setDbEntry(result);
};
fetchData();
}, []);
console.log(dbEntry[0]); // <-- Works (shows [RowDataPacket] object)
console.log(dbEntry[0].ID); // <-- TypeError: Cannot read property '0' of undefined
return (
<p>
{dbEntry[0].ID} // <-- How do I render here?
</p>
)
}
What's going on here? I have a feeling React is coercing the result object somehow, but I can't figure it out...
When you need to display data that comes from an async font(API calls for example), it's possible (actually almost certain) that it won't be available by the time the first render occurs, to solve that there is actually a few things you could do:
Placeholder state
You could have a model of what the data will look like described as your initial state, so properties won't be undefined anymore:
const [state, setState] = useState({
data:[
{name: ''}
]
})
Assuming that your data will have this format accessing state.data[0].name won't throw an error. This could be useful in some cases but I personally don't like the approach.
Conditional Render
At each render you should check for a condition and only if satisfied render the piece of code:
return(
<>
<div>Title</div>
{Boolean(state.data.length) && <div>{state.data[0].name}</div>}
</>
)
Suspense
That one is brand new, if you have a component tha't need to perform side effects before render it's content, you should have a fallback content to be displayed while the async action is being perform.
<Suspense fallback={<span>Loading</span>}>
<MYAsyncComponent />
</Suspense>
I am trying to select all records from table called fairCustomer where business_type_id equal array of value.
I am using sailsjs for server and mysql for DB, in frontend I am using nativescript with typescript.
and this is my code:
filterShopType(){
this.service.serviceName = 'fairCustomers';
this.service.Get({ populate:'country_id,business_type_id',where:{ business_type_id:{ in:this.business_ids_filter } }, limit:20 }).then((data: any) => {
this.fairCustomers.splice(0, this.fairCustomers.length);
this.fairCustomers.push(data);
this.Refresh('fairCustomers');
}).catch((err) => {
console.log('failed get fairCustomers from server ', err);
});
}
service refer to http.request(), where i am using it in another place in my code.
business_ids_filter is an array of ids.
When I run this code the I am getting this error:
"message": "Could not parse the provided where clause. Refer to the Sails documentation for up-to-date info on supported query language syntax:\n(http://sailsjs.com/documentation/concepts/models-and-orm/query-language)\nDetails: Unrecognized sub-attribute modifier (in) for business_type_id. Make sure to use a recognized sub-attribute modifier such as startsWith, <=, !, etc. )",
and if I removed where I got an error result.
please anyone have any idea or solution?
you may try with a native query as described here, https://sailsjs.com/documentation/reference/waterline-orm/datastores/send-native-query
As far as I can tell, you could simply provide an array of items. Matches against ANY of the items in the array means that the record should be returned as part of the result. Not sure if it works in a where-clause though.
Docs:Query Language (scroll to: In Modifier)
I do share your confusion as to why the given query does not work though, as the docs state that in should be valid, but perhaps it's not valid inside where:{...}? And I am assuming you are using .find() inside .Get(...)? Simply proxying the query unchanged through to .find()?
filterShopType(){
this.service.serviceName = 'fairCustomers';
this.service.Get({
populate:'country_id, business_type_id',
business_type_id: this.business_ids_filter,
limit:20
})
.then((data: any) => {
this.fairCustomers.splice(0, this.fairCustomers.length);
this.fairCustomers.push(data);
this.Refresh('fairCustomers');
}).catch((err) => {
console.log('failed get fairCustomers from server ', err);
});
}
Now, you of course need to make sure that the array actually is an array if you use in:.
It is working with me by using [or] instead of [in], this is the code
filterShopType(){
if(this.business_ids_filter){
this.service.serviceName = 'fairCustomers';
var arr = [];
this.business_ids_filter.forEach( (id) => {
arr.push({ business_type_id: id })
});
let where = {};
if(arr.length > 0){
where = {or: arr};
}
this.service.Get({ populate: 'country_id,business_type_id',where:where , limit:20 }).then((data: any) => {
this.filterItems.splice(0, this.filterItems.length);
this.filterItems.push(data);
this.Refresh('filterItems');
}).catch((err) => {
console.log('failed get fair Customers from server ', err);
});
}else{
this.set('isFilter', false);
}
}
I have some code which polls until a task is complete
See below
this.simulationStatus =
interval(2000).pipe(
switchMap(
() => from(this.simulationService.getSimulationStatus(this.route.snapshot.paramMap.get('jobId')))),
takeUntil(this.stopPoll),
tap(simulation => {
if (simulation && simulation.complete) {
if (this.stopCount == 1) {
// Get once after complete
this.stopPoll.next(true);
}
this.stopCount++;
}
})
);
I have tried using takeUntil and takeWhile the problem is that that the last value is never published once the task is complete.
To get around this I have to include the tap method to with the stopPoll subject and incrementing the stopCount to get the last value.
So the above works but just feels a bit messy, I'm sure there must be a better way of achieving this?
I would have expected takeUntil to publish the last value or have an override to tell it to e.g takeUntil(observable, {publishLast: true})
BTW Update, the observable is subscribed to by an Angular 6 template
Thanks in advance
One thing you can do is use a custom takeWhile-like operator like this:
const completeWith = <T>(predicate: (arg: T) => boolean) => (
source: Observable<T>,
) =>
new Observable<T>(observer =>
source.subscribe(
value => {
observer.next(value);
if (predicate(value)) {
observer.complete();
}
},
error => observer.error(error),
() => observer.complete(),
),
);
It doesn't seem like a good idea to see it as a variation of takeWhite because it's not just taking values while a condition holds, but also emits an extra value.
It might be that a more elegant solution would be make the simulation status observable emit two kinds of values: next notifications and completion notifications, similarly to how materialize/dematerialize operators work.
This has in the meantime been implemented in rxjs as takeWhile(condition, ?inclusive):
timer(0, 10).pipe(
takeWhile((x) => x < 3, true)
)
emits 0, 1, 2, 3
You can also create subject and emit using next() if you want to complete the observable.
this.stopPoll: Subject<any> = new Subject<any>();
If you want to do complete the subscription. you can call this.stopPoll.next(true);
you can access the data in subscribe()
this.simulationStatus.subscribe(success=>{}, failure=>{}, complete=>{});