Page not refreshed when clicked delete button in angular - javascript

I have a page running at "http://localhost:4200/assignmentForAudit" and the UI looks like
When i click delete button then the data gets deleted but the page is not refreshed. I tried to put this.router.navigate(['/assignmentForAudit']); after delete operation but it is not refreshing the page.How can i achieve this refresh method so that the data gets removed?
method to delete in component.ts
onDelete(nas:any){
this.assignmentAudit.id=nas.assignmentAudit[0].id;
console.log(this.assignmentAudit.id);
if(window.confirm('Are sure you want to delete this item ?')){
this.assignmentAuditService.deleteGroupFromSelection(this.assignmentAudit.id)
.subscribe(
data => {
console.log(data);
},
error => console.log(error));
}
this.router.navigate(['/assignmentForAudit']);
}
assignment-audit.service.ts class method to call the api operation
deleteGroupFromSelection(id: number): Observable<any> {
return this.http.delete(`${this.baseUrl}/${id}`, { responseType: 'text' });
}
Delete operation is working fine but the problem is the page is not refreshing.

that's not recommended at all as a best practice when you using angular you can simple emit data list after every delete with that you update the data visually too but if you want such behavior.
First Case by reload the whole page you can do so after every delete
window.location.reload();
Second Case if you need just to reload the component you can work around that and achieve it by a hack (just to trick the component you navigate away and navigate again to it)
this.router.navigateByUrl('/DummyComponent', {skipLocationChange: true}).then(() => this.router.navigate(['Your actualComponent you want to reload']));
/DummyComponent could be a empty component you just gonna use it to trick the actual component you need to refresh/reload

Instead of trying to reload the page, call the http method which is used to populate the entries again on success of the delete http call.
this.assignmentAuditService.deleteGroupFromSelection(this.assignmentAudit.id)
.subscribe(
data => {
this.entries = this.http.get() // something like this. here this.entries refers to data that is used to populate html.
console.log(data);
},
error => console.log(error));
}
You can also use a BehaviorSubject to emit a value, listening to it, you can decide on calling this.entries = this.http.get() again.

You may need to use the 'onSameUrlNavigation' option in Angular routes.
RouterModule.forRoot(routes, {onSameUrlNavigation: ‘reload’})

Can your show how to binding array of object to template ? I thinks you just remove item from array then template it will update data too.
something like this:
this.nas.assignmentAudit = this.nas.assignmentAudit.filter(a => a.id !== this.assignmentAudit.id);

Related

Angular subscribes not working how I expect

I'm at a loose end here and trying to understand the flow of how angular subscriptions work.
I make a call to an API and in the response I set the data in a behaviourSubject. So I can then subscribe to that data in my application.
Normally I would use async pipes in my templates cause its cleaner and it gets rid of all the subscription data for me.
All methods are apart of the same class method.
my first try.....
exportedData: BehaviourSubject = new BehaviourSubject([]);
exportApiCall(id) {
this.loadingSubject.next(true)
this.api.getReport(id).pipe(
catchError((err, caught) => this.errorHandler.errorHandler(err, caught)),
finalize(() => => this.loadingSubject.next(false))
).subscribe(res => {
this.exportedData.next(res)
})
}
export(collection) {
let x = []
this.exportCollection(collection.id); /// calls api
this.exportedData.subscribe(exportData => {
if(exportData){
x = exportData
}
})
}
console.log(x)//// first time it's empthy, then it's populated with the last click of data
/// in the template
<button (click)="export(data)">Export</button>
My problem is....
There is a list of buttons with different ID's. Each ID goes to the API and gives back certain Data. When I click, the console log firstly gives a blank array. Then there after I get the previous(the one I originally clicked) set of data.
I'm obviously not understanding subscriptions, pipes and behavior Subjects correctly. I understand Im getting a blank array because I'm setting the behaviour subject as a blank array.
my other try
export(collection) {
let x = []
this.exportCollection(collection.id).pip(tap(res => x = res)).subscribe()
console.log(x) //// get blank array
}
exportApiCall(id) {
return this.api.getReport(id).pipe(
catchError((err, caught) => this.errorHandler.errorHandler(err, caught))
)
}
Not sure about the first example - the placement of console.log() and what does the method (that is assigned on button click) do - but for the second example, you're getting an empty array because your observable has a delay and TypeScript doesn't wait for its execution to be completed.
You will most likely see that you will always receive your previous result in your console.log() (after updating response from API).
To get the initial results, you can update to such:
public exportReport(collection): void {
this.exportCollection(collection.id).pipe(take(1)).subscribe(res => {
const x: any = res;
console.log(x);
});
}
This will print your current iteration/values. You also forgot to end listening for subscription (either by unsubscribing or performing operators such as take()). Without ending listening, you might get unexpected results later on or the application could be heavily loaded.
Make sure the following step.
better to add console.log inside your functions and check whether values are coming or not.
Open your chrome browser network tab and see service endpoint is get hitting or not.
check any response coming from endpoints.
if it is still not identifiable then use below one to check whether you are getting a response or not
public exportReport(collection): void {
this.http.get(url+"/"+collection.id).subscribe(res=> {console.log(res)});
}
You would use BehaviourSubject, if there needs to be an initial/default value. If not, you can replace it by a Subject. This is why the initial value is empty array as BehaviourSubject gets called once by default. But if you use subject, it wont get called before the api call and you wont get the initial empty array.
exportedData: BehaviourSubject = new BehaviourSubject([]);
Also, you might not need to subscribe here, instead directly return it and by doing so you could avoid using the above subject.
exportApiCall(id) {
this.loadingSubject.next(true);
return this.api.getReport(id).pipe(
catchError((err, caught) => this.errorHandler.errorHandler(err, caught)),
finalize(() => => this.loadingSubject.next(false))
);
}
Console.log(x) needs to be inside the subscription, as subscribe is asynchronous and we dont knw when it might get complete. And since you need this data, you might want to declare in global score.
export(collection) {
// call api
this.exportApiCall(collection.id).subscribe(exportData => {
if (exportData) {
this.x = exportData; // or maybe this.x.push(exportData) ?
console.log(this.x);
}
});
}

React - useEffect

So i have a simple to-do app, click here to [Link removed].
The problem i have is that in Console > Network i get too many same GET requests so it looks like
i have an infinite loop. Im probably not coding this right in useEffect, since the effect triggers my http get methods which contain setTodos(data) which makes it trigger useEffect again.
What im trying to achieve is the same functionality that the web app has right in this moment, but with appropriate coding:
Fetching the appropriate data every time user clicks some category.
I also want to trigger fetch for specific category each time user either adds/edits/deletes a 'todo' so i can achieve 'live feed'.
EDIT : What i tried right now is implementing useState [test,setTest]. I added setTest(!test) to my funcs: addTodo, removeTodo, markTodo and to my category btn onClick func. I also put [test] to dep. array in my useEffect. Sometimes list updates correctly, sometimes it doesnt at all, and sometimes it udpates but incorrectly (ex: when i mark a todo, it gets marked/crossed and then it gets unmarked 1sec after. But if i refresh the page its ok).
useEffect
useEffect(() => {
if(filter === 'Completed')
httpRequestHandler(`${baseAPIurl}/completed`, "GET");
else if(filter === 'Active')
httpRequestHandler(`${baseAPIurl}/notcompleted`, "GET");
else
httpRequestHandler(`${baseAPIurl}/todos`, "GET");
});
And here is part of my httpRequestHandler function
const httpRequestHandler = async (url, type, data) =>
{
let request = {}
if(type === 'GET')
{
request = {
method: "GET",
headers: {"Content-type": "application/json"}
};
await fetch(url, request)
.then((response)=> {
return response.json();
})
.then((data)=> {
setTodos(data);
});
return;
}
...........................
}
Depending on the rest of your code, you need to adjust the dependency array
more info, eg. here
Have you tried adding filter into dependency array to only update on filter change?
useEffect(() => { ... }, [filter])
No idea what was causing my useEffect not to trigger in the first place, i already tried this but now it works (no idea why). What i did is:
Implemented useState [trigger, setTrigger]
In my httpHandler func (which handles http requests), specifically in PUT/DELETE/POST part of the func where i use fetch(--, --) i added setTrigger(!trigger) to .then() part.
Added [trigger] to useEffect dependency array

dynamically adding cards to the screen after sending a post request to database in Vuejs

I want to refresh my cardData array that gets its value by a get request from the database after I send a post request the the database. I have written this saveDraft() function that upon click adds values to cardData array but I need to refresh the page or click on it twice to see the changes. Is there a way to do it dynamically without refreshing the page?
saveDraft() {
Api.createComment({
// it's a post request
})
.then(res => {
if (response.status == 200) {
Api.getComments().then(res => {
// it's a get request to update the cardData
if (res.status === 200) {
this.cardData = res.data;
} else {
// catches error
}
});
} else {
// catches error
}
});
},
I can't exactly see how you've implemented the saveDraft() function but I'll work with what you gave!
To generally answer your question, I think it depends on what you mean by clicking on it twice or refreshing the page (i.e. 'clicking' meaning you've bound it to a user event such as #dblclick or #click?). But in Vue, you can handle dynamic events through the following:
1) Is this function in a child component? If yes, then consider using v-on directive to listen to user events (i.e. #dblclick, #click, #mouseover, etc.), emitting a custom event, or creating a watcher that 'updates' the data in a parent.
If this is confusing, you can check out the video by Vue Mastery on event handling that goes over the foundations of emitting events from the child component to the parent.
2) You can consider using Vuex as a state-manager. This can help with reactivity - of updating a component or piece of data being passed around through mutations and actions. Check out a general overview of Vuex and reactivity in Vue on Vue Mastery
If this still doesn't make sense, let me know here or update your question if needed :)

React Router -- history push state not refreshing with new state object

When Promise.all resolves and the new activity is saved, the user should be routed to /activities to view their newly created activity. Everything works as expected, however I currently need to refresh /activities page (once) after being routed in order to view the new activity in the table.
const handleSaveActivity = e => {
e.preventDefault();
Promise.all([
addActivity(),
saveActivity()
]).then(() => {
props.history.push('/activities');
})
};
I'm not sure how to re-render the page automatically after pushing a new history state, so the user does not need to manually refresh the page to see the new state. Happy to provide more code snippets if I left out something critical.
Hi i must be a little late to answer this, but this issue can be due to the wrong use of useEffect, if you have lets say a todo list and you wanna fetch data with axios for example, it would look like this:
useEffect(()=>{
axios.get(`${YOUR_URL}/todos`)
.then((res)=>{
setTodos(todos=res.data)
})
},[])
now as you can see we have initial value of an empty array, so this is acting as a ComponentDidMount, what you might want is to re render the component after it gets a new value, so you want to have a ComponentDidUpdate effect, so you would just not initialize the value as an empty array, therefore it would look like this:
useEffect(()=>{
axios.get(`${YOUR_URL}/todos`)
.then((res)=>{
setTodos(todos=res.data)
})
})
Hope this helps someone, couse i landed here due to the same issue and came to solve it this way.
just to run this.setState({whateverKey:whateverValue})?
In your activities page (call it Activities component) you should call API to get the updated data every time browser hit this component URL.
With class based style, you should do it in componentDidMount life cycle hook
class Activities extends Component {
// ...
componentDidMount() { loadActivities() }
// ...
}
With function based style, you should do it in useEffect hook
import React, { useEffect } from 'react'
const Activities = () => {
useEffect(() => { loadActivities() });
}
https://github.com/supasate/connected-react-router Please use this package, it solves the problem.
This issue I've faced a few minutes ago...however I finally found the solution by manually using the vanilla javascript. => for refreshing the page you can use
=> window.location.reload(false); after using the push property.

Multiple Subscriptions to same Subject/Observable on multiple method calls

I have a button, upon clicking which, I subscribe to a "data load". Upon successful data load, I have to display a modal.
Here's my code:
Subject and Observable:
dataSubject = new Subject<boolean>();
isDataLoaded$: Observable<boolean> = this.dataSubject.asObservable();
Fetch Data Method:
(This is a separate method because it is being used in multiple places and not only for populating the modal data.)
fetchData() {
this.dataSubject.next(false);
...
// Fetch Some Data
...
this.dataSubject.next(true);
}
Button Click method:
buttonClick() {
// fetch data
this.fetchData();
// once the data is loaded, display the modal
this.dataSubscription = this.isDataLoaded$.subscribe((isDone) => {
if (isDone) {
this.displayModal();
}
});
}
When i click the button the first time it works fine and displays a modal. When I click second or more times, I get multiple instances of the modal pop up. From what I understand, I am subscribing multiple times and hence the multiple modals.
I have also tried unsubscribing before subscribing, to make sure i have a single subscription, but even then I get atleast 2 modals that pop up.
Is the a clean way to implement my requirement? TIA
You don't need seperate isDataLoaded$ I think. Just subscribe to dataSubject but not inside buttonClick. You trigger the serivce with call to fetchData no need subscription to be inside function.
this.dataSubscription = this.dataSubject.subscribe((isDone) => {
if (isDone) {
this.displayModal();
}
});
buttonClick() {
// fetch data
this.fetchData();
}

Categories

Resources