Parsing data from service to component in angular - javascript

In my service I make a call:
this.potentialOrganizations(currentNode.id)
.subscribe(data => {
console.log('consoling the org data!!!!!!! ' + JSON.stringify(data))
this.potentialOrgData = [];
this.potentialOrgData = data;
this._potentialOrgs.onNext(true);
})
The data consoles fine, as you can see, I tried using an observable method but it's not working for some reason!
I may need a new way to be able to call the data, as I said in my components html I have this: although it doesn't work:
<ul *ngIf="this.engagementService.potentialOrgData.length > 0">
<li *ngFor="let org of this.engagementService.potentialOrgData">
<p class="listedOrgs">{{ org.name }}</p>
</li>
</ul>
In my component I had this:
ngOnInit(): void {
this.engagementService.potentialOrgs$.subscribe(
(data) => {
if (data) {
console.log('are we hitting here inside the potentialORG DATA!??!?!?!!?!?')
this.potentialOrganizations = this.engagementService.potentialOrgData;
}
}
)
this.potentialOrganizations = this.engagementService.potentialOrgData;
}
it doesnt console, even though in my service i have the observable thing set:
private _potentialOrgs = new BehaviorSubject<boolean>(false);
public potentialOrgs$ = this._potentialOrgs.asObservable();
I was thinking maybe I need to use #input instead? but how to do that properly?

You could make this a little more simple here by trying the following. If potentialOrgData is set from a subscription in the service which it is, it will stay fresh as subscriptions stay open. You will be able to use the variable in the service directly.
public requestedData = [];
public ngOnInit(): void {
this.requestedData = this.engagementService.potentialOrgData;
}
In your template.
<ul *ngIf="requestedData.length">
<li *ngFor="let org of requestedData">
<p class="listedOrgs">{{ org.name }}</p>
</li>
</ul>
Behaviour Subjects and Observable's are very powerful but not always necessary.

Related

Make button to wait for mehtod to resolve

I have a couple of buttons that I want to display only if user is logged in. My problem is that simple *ngIf is not working like I want it to.
For example I have this button Add Recipe:
<div class="background">
<button type="button" *ngIf="isUserAuthenticated" class="btn btn-primary float-right m-2" data-bs-toggle="modal" data-bs-target="#exampleModal"
(click)="addClick()"
data-backdrop="static"
data-keyboard="false">
Add Coffee
</button>
It is button for showing modal. I want that button to be displayed only if user is authenticated. This is how my .ts looks like:
export class RecipeDetailsComponent implements OnInit {
...
public isUserAuthenticated: boolean = false;
ngOnInit(): void {
this.userService.authChanged
.subscribe(res => {
this.isUserAuthenticated = res;
})
}
and my userService methods for checking if authenticated:
export class UserService {
private _authChangeSub = new Subject<boolean>()
public authChanged = this._authChangeSub.asObservable();
public sendAuthStateChangeNotification = (isAuthenticated: boolean) => {
this._authChangeSub.next(isAuthenticated);
}
public isUserAuthenticated = (): boolean => {
const token = localStorage.getItem("token");
return token != null && this._jwtHelper.isTokenExpired(token) == false;
}
Button appears only If i set isUserAuthenticated = true when declaring and hides if it false.
I guess button reads isUserAthenticated property and show it selfs before ngOnInit.
How can I delay button display till ngOnInit is resolved or just refresh after that?
If I understand your question, You're having trouble because of timing. Your code doesn't include when or how the value changes but I am guessing that the value is changed before your component initializes and therefore you are subscribing late?
If so, I recommend changing
private _authChangeSub = new Subject<boolean>()
to
private _authChangeSub = new ReplaySubject<boolean>(1);
This way, even when subscribing after the value has been emitted, the component will still receive the value. See https://www.learnrxjs.io/learn-rxjs/subjects/replaysubject

Saving Values to Backend from TextBoxes using React Flux Pattern

I have several text boxes and a save button
Each text box value is loaded using the following approach
{
this.getElement('test3lowerrangethreshold', 'iaSampling.iaGlobalConfiguration.test3lowerrangethreshold',
enums.IASamplingGlobalParameters.ModerationTest3LowerThreshold)
}
private getElement(elementid: string, label: string, globalparameter: enums.IASamplingGlobalParameters): JSX.Element {
let globalParameterElement =
<div className='row setting-field-row' id={elementid}><
span className='label'>{localeHelper.translate(label)}</span>
<div className="input-wrapper small">
<input className='input-field' placeholder='text' value={this.globalparameterhelper.getDataCellContent(globalparameter, this.state.globalParameterData)} />
</div>
</div>;
return globalParameterElement;
}
Helper Class
class IAGlobalParametesrHelper {
public getDataCellContent = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>) => {
return configdata?.find(x => x.key === globalparameter)?.value;
}
}
This works fine. Now the user is allowed to update these text values.And on click of save the changes should be reflected by calling a web api .
I have added an onlick event like this
<a href='#' className='button primary default-size' onClick={this.saveGlobalParameterData}>Save</a>
Now inorder to save the data i need a way to identify the text element which has changed.For that i have added an update method within the Helper class
public updateCellValue = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>,updatedvalue:string) => {
let itemIndex = configdata.findIndex(x => x.key === globalparameter);
configdata[itemIndex] = updatedvalue;
return configdata;
}
and return the updated configdata ,and i plan to call this method in the onchange event of every text box like this
<input className='input-field' placeholder='text' onchange={this.setState({ globalParameterData: this.globalparameterhelper.updateCellValue(globalparameter, this.state.globalParameterData, (document.getElementById(elementid) as HTMLInputElement).value})}
But this does not seem like a correct approach as there are number of syntactical errors. I initially got the data using an actioncreator like this.Please advice.
samplingModerationActionCreator.getGlobalParameters();
samplingModerationStore.instance.addListener(samplingModerationStore.SamplingModerationStore
.IA_GLOBAL_PARAMETER_DATA_GET_EVENT,
this.getGlobalParameterData);
}

Angular - Update data automatically without Refresh the Page

In my application there is a table that get rows from database.
This is the AJAX CALL (SERVICE)
getPosts(): Observable<Posts[]> {
return this.http.post<Posts[]>(this.myAppUrl + this.myApiPostsUrl, this.authService.getLoggedUserFromSessionStorage())
.pipe(
retry(1),
catchError(this.errorHandler)
);
}
All work perfectly, but my datas dont update automatically, and the user need to refresh the page to see the new rows, how can i do this?
I would like do that the new rows are added in the table dynamically ... without update the page.
This is the table
COMPONENT HTML
<table *ngIf="(posts$ | async)?.length>0" class="table align-items-center table-flush">
.....
<tr *ngFor="let post of (posts$ | async) | filter:authService.filter | paginate: config | orderBy: key : reverse">
<!-- <td>{{posts.id}}</td>-->
<td>{{post.title}}</td>
<td>{{post.body}}</td>
.....
</table>
COMPONENT TS
ngOnInit() {
this.loadPosts();
}
loadPosts() {
this.message = 'Loading....';
this.posts$ = this.postService.getPosts();
if (this.posts$ == null) {
this.message = 'No Posts found';
}
}
Thanks so much.
There are several options. Here is a reactive way of handling this. Any time getPosts is successful, you'll need to refetch the initial data.
To fetch your initial data you will need to wrap your posts$ observable in an action stream:
// create a stream for your post request
private readonly postAction$ = new Subject();
posts$ = this.postAction$.pipe(
startWith(''),
concatMap(()=> {
return this.postService.getPosts(); // this will be your http get request
}),
)
The startWith operator will cause your get request to fire initially without an observable been passed to your postAction observable.
Your getPosts method now will call this.postAction$.next() on success, that will trigger the refetch of your posts$ observable.
getPosts(): Observable<Posts[]> {
return this.http.post<Posts[]>(this.myAppUrl + this.myApiPostsUrl, this.authService.getLoggedUserFromSessionStorage())
.pipe(
retry(1),
catchError(this.errorHandler),
tap(() => this.postAction$.next())
);
}
You can see a demo of this. Check the console, you'll see that the get request is fired every time the button is clicked.
With Interval
posts$ = interval(30000)
.pipe(
startWith(''),
switchMap(() => return this.postService.getPosts();)
)
Interval demo
in Angular, when you want to update your html, you need to use ngFor to update your data automatically.
<table *ngIf="(posts$ | async)?.length>0" class="table align-items-center table-flush">
<div *ngFor="let data of datas; let i = index>
{{ data }}
</div>
</table>
ngFor will loop on datas and update it when it changes

Angular directive ngIf is not working as expected

We are trying to pass data from one component to another and below is the approach we are taking. When there is no data we want to show the error message
<div *ngIf="showGlobalError">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
and the component.ts is like
showGlobalError = true;
constructor(private psService: ProjectShipmentService, private pdComp: ProjectDetailsComponent) {
this.psService.tDate.subscribe(x => this.cachedResults = x);
}
ngOnInit() { }
ngDoCheck() {
if (this.cachedResults.length > 0 && this.count <= 1) {
this.showGlobalError = false;
this.populateArrays();
this.count++;
}
}
populateArrays() {
this.reportingProject = [this.pdComp.rProjectNumber];
this.projectSalesOrder = this.pdComp.rSalesOrder;
this.clearFilter();
........
The issue is Even though there is data in the this.cachedResults that is this.cachedResults.length not equal to '0' for few seconds 'The reporting project doesn't have any Shippable Items' is shown in the page and then shows the data I am not sure if this something with the ngDoCheck() is causing this. Any help is greatly appreciated
Since, the default value of showGlobalError is true, the page load shows the error message.
Please make it by default false and make it true when this.cachedResults.length is 0 or this.cachedResults is undefined or this.cachedResults is null.
Hope this solves your problem.
Rather than subscribing in the code you can use the async pipe in your template
items$ = this.psService.tDate;
showGlobalError$ = this.items$.pipe(map(results => !results || !results.length));
constructor(private psService: ProjectShipmentService, private pdComp: ProjectDetailsComponent) { }
and in your template
<div *ngIf="showGlobalError$ | async">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
<ng-template *ngFor="let item of items$ | async">
Do stuff with {{item | json}}
</ng-template>
This manages your subscription for you and fixes the memory leak you have in your code with the subscription you don't unsubscribe from.
Take a look at alibrary I wrote for this sort of thing, make caching data a lot easier. https://medium.com/#adrianbrand/angular-state-management-with-rxcache-468a865fc3fb

Angular 4 ngIf not toggled after variable being updated in ngOnInit

I am using Angular v4 and have a *ngIf in my template:
<div class="product-list row" *ngIf="products.length > 0">
<div *ngFor="let product of products" class="product-container">
...
</div>
</div>
and in my component file I have:
public products = [];
....
public ngOnInit(): void {
this.productsService.all().toPromise().then( (data: Product[]) => {
this.products = data;
});
}
However the ngIf will not be toggled after products is set. When I add a button and set the variables manually the ngIf will be toggled!
I tried changing the if statement to products?.length > 0 but it doesn't work as well.
Found my answer from this post:
Triggering change detection manually in Angular
According to Angular's documents https://angular.io/api/core/ChangeDetectorRef
detectChanges(): Checks the change detector and its children.
So by applying detectChanges Angular will manually check and update the node.

Categories