Sharing JSON data from server between 2 components

自作多情 提交于 2019-12-31 05:15:06

问题


I posted this yesterday but I have changed so much of the code today I have basically re-written my question:

I have a NativeScript with Angular app using the TabView template and a login form using a modal window over the tabs initially and this appears to be working OK - the login form has no tabs and when logged in I am taken to the TabView.

Upon successful login I want to call methods within the tabbed components and update the respective templates with content specific to the logged in user.

For example one of these is a list of user reports.

I am trying to get a list of user reports from our server and display the list in reports.component.html by calling a service from the success handler in login.component.ts then accessing this in reports.component.ts

In login.component.ts I have at the top

    ...
import { User } from "../shared/user/user.model";
import { UserService } from "../shared/user/user.service";
import { ReportsComponent } from "../reports/reports.component";
import { UpdateService } from "../shared/update.service";
...

...
@Component({
    selector: 'login',
    moduleId: module.id,    
    providers: [UserService, ReportsComponent, ReportService, UpdateService ],
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
})
...

In the constructor I have

private userService: UserService,
private repts: ReportsComponent,
private reportService: ReportService, 
private updateService: UpdateService,

Then I have

public login() {

   this.userService.login(this.user)
   .subscribe(
        (data) => {              
            //console.log("login data in component = "+JSON.stringify(data));  


            if (data.authenticated==false) {
                ApplicationSettings.setBoolean("authenticated", false);
                alert("Unfortunately we could not log you in: "+data.message);
            } else if (data.authenticated==true) {
                ApplicationSettings.setBoolean("authenticated", true);
                ApplicationSettings.setString("token", data.token);

                console.log("authenticated="+ApplicationSettings.getBoolean("authenticated"));
                console.log("Login success! token="+data.token);

                console.log("calling updateReports from update.service.ts");

                this.updateReports();       

                //this.expense.populate_reports(this.expense); 
                //this.expense.populate_categories(this.expense); 

                this.modalDialogParams.closeCallback(() => console.log('Login modal closed'));

            }

        },
        (error) => alert("Unfortunately we could not log you in.")
   );        
}    
public updateReports() {
    this.updateService.getReports()
    .subscribe(
        (data) => {              
            //console.log("report data in login component = "+JSON.stringify(data));  
        },
        (error) => alert("Problems...")
   );         
}

In update.service.ts I have

@Injectable()
export class UpdateService {

private _expenses: ObservableArray<Expense>;

private reportDataSource = new Subject<string>(); // Source
reportData$ = this.reportDataSource.asObservable(); // Stream

constructor(private http: Http) { }


getReports() {
    console.log("in updateService getReports");

    let url = Config.apiUrl + "ns_get_reports.php";
    //console.log(url);
    return this.http.get(
        url,
        { headers: this.getCommonHeaders() }
    ).pipe(
        map(this.extractData),
        tap(data => {
            //alert("oi");
            this.reportDataSource.next(data);
            //console.log("reports listing in update service = "+JSON.stringify(data));
        }),
        catchError(this.handleErrors)
    );
}       
getCommonHeaders() {
    let headers = new Headers();
    let token=ApplicationSettings.getString("token");        
    headers.append("Content-Type", "application/json");
    headers.append("token", token);
    return headers;
}
handleErrors(error: Response) {
    console.log(JSON.stringify(error.json()));
    return Observable.throw(error);
}
private extractData(res: Response) {
    let body = res.json();
    return body || {};
}    

}

Then in reports.component.ts I have

export class ReportsComponent implements OnInit {

//private report: Report;
private _reports: ObservableArray<Report>;
private _expenses: ObservableArray<Expense>;
header: string;
report_status: Array<String>;

subscription: Subscription;

constructor(private router: Router, 
    private reportService: ReportService, 
    private expenseService: ExpenseService,
    private _changeDetectionRef: ChangeDetectorRef, 
    private updateService: UpdateService) {

    this._reports = new ObservableArray<Report>();
    this.subscription = updateService.reportData$.subscribe(
        (res) => {
            console.log("reports listing in reports component = "+JSON.stringify(res));

            let data=JSON.parse(JSON.stringify(res));

            if (data["reports"]=="No Reports") {                 
                // No reports to show
            } else {  
                var status_text;
                var status_class;
                for (let i = 0; i < data.reportid.length; i++) {
                    var status_codes=this.displayReportStatus(data.report_status[i]);
                    status_text=status_codes[0];
                    status_class=status_codes[1];

                    this._reports.push(new Report(data.reportid[i], data.report_name[i], data.report_status[i], data.report_value[i], status_text, status_class, data.report_justification));
                }
                this._changeDetectionRef.markForCheck();
                if (!this._changeDetectionRef['destroyed']) {
                    this._changeDetectionRef.detectChanges();
                }

            }

        }
    );
}
public get reports(): ObservableArray<Report> {
    return this._reports;
} 

The line

console.log("reports listing in reports component = "+JSON.stringify(data));

is outputting the reports data no problem so the service is returning the correct data.

However the template is not displaying the formatted list of reports. It is blank. The template looks like:

   <!--
    <RadListView [items]="reports" (itemTap)="onReportItemTap($event)" >
    //-->
    <RadListView [items]="reports" >
        <ng-template tkListItemTemplate let-item="item">
            <StackLayout class="itemTemplateStackLayout" orientation="vertical">

                    <StackLayout class="reportStackLayout" orientation="vertical">

                        <Label class="labelName blue_text bold_text list-group-item" [nsRouterLink]="['../report', item.reportid]" [text]="item.report_name"></Label>


                        <GridLayout class="reportDetailsGridLayout" columns="*, *">
                            <Label row="0" col="0" horizontalAlignment="left" [class]="item.status_class" class="labelStatus"  [text]="item.status_text" textWrap="true"></Label>
                            <Label row="0" col="1" horizontalAlignment="right" class="labelValue green_text bold_text" [text]="item.report_value" textWrap="true"></Label>
                        </GridLayout>

                    </StackLayout>

            </StackLayout>
        </ng-template>         
    </RadListView>
</GridLayout>

Any ideas what I am doing wrong.

Hope I have explained sufficiently - please let me know if I need to clarify anything further.

Thanks.

EDIT: October 9th.

Here is the reports.component.ts as it is now. Still not updating the view.

import { Component, ChangeDetectorRef, OnInit } from "@angular/core";

import { ReportComponent } from "./report.component";
import { Report } from "../shared/report/report.model";
import { Expense } from "../shared/expense/expense.model";
import { ReportService } from "../shared/report/report.service";
import { ExpenseService } from "../shared/expense/expense.service";
import { UpdateService } from "../shared/update.service";
import { Subject, Subscription } from 'rxjs';
import { ActivatedRoute, Router } from "@angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router"; 
import { Page } from "tns-core-modules/ui/page";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { ListViewEventData } from "nativescript-ui-listview";
import { RadListView } from "nativescript-ui-listview";


import { RouterExtensions } from "nativescript-angular/router";
import * as ApplicationSettings from "application-settings";
import {getBoolean, setBoolean, getNumber, setNumber, getString, setString, hasKey, remove, clear} from "tns-core-modules/application-settings";
import { Injectable } from "@angular/core";

declare var module: {
    id: string;
 }
@Component({
selector: "Reports",
moduleId: module.id,
providers: [ReportService, ExpenseService, UpdateService],
templateUrl: "./reports.component.html",
styleUrls: ["./reports.component.css"]
})


export class ReportsComponent implements OnInit {

//private report: Report;
private _reports: ObservableArray<Report>;
private _tempreports: ObservableArray<Report>;
private _expenses: ObservableArray<Expense>;
header: string;
report_status: Array<String>;
isLoading = true;
foo: string;

private listView: RadListView;

subscription: Subscription;

constructor(private router: Router, 
    private route: ActivatedRoute,
    private reportService: ReportService, 
    private expenseService: ExpenseService,
    private _changeDetectionRef: ChangeDetectorRef, 
    private updateService: UpdateService) {

        this.subscription = this.updateService.reportData$.subscribe(
            (res) => {
                console.log("isLoading="+this.isLoading);
                console.log("reports listing in reports component = "+JSON.stringify(res));


                this._reports = new ObservableArray<Report>();
                this._tempreports = new ObservableArray<Report>();

                let data=JSON.parse(JSON.stringify(res));

                if (data["reports"]=="No Reports") {                 
                    // No reports to show
                } else {  
                    var status_text;
                    var status_class;
                    for (let i = 0; i < data.reportid.length; i++) {
                        var status_codes=this.displayReportStatus(data.report_status[i]);
                        status_text=status_codes[0];
                        status_class=status_codes[1];

                        this._tempreports.push(new Report(data.reportid[i], data.report_name[i], data.report_status[i], data.report_value[i], status_text, status_class, data.report_justification));
                    }
                    this._reports = this._tempreports;
                    this._changeDetectionRef.markForCheck();
                    if (!this._changeDetectionRef['destroyed']) {
                        this._changeDetectionRef.detectChanges();
                    }

                    this.isLoading=false;
                    //this.listView.refresh();                      
                    console.log("isLoading="+this.isLoading);   

                }

            }
        );

}
onListLoaded(args) {
    console.log("In onListLoaded");
    this.listView = args.object;
    this.listView.refresh();     
}

public get reports(): ObservableArray<Report> {
    //console.log("Where are the focking reports");
    return this._reports;
} 

回答1:


Which platform(ios/android) are you testing this? It is very important for ios to provide height and width to the listview or it's parent component. otherwise You code looks fine to me at very first glance. There are couple of other thing you could to try for further debugging

  1. Subscribe in (loaded) mthod of RadListView.

  2. Try to assign listview in loaded like this

onListLoaded(args) {this.listView = args.object;}

and refresh the listview by this.listview.refresh() once you have the reports data. 3. Have an activityIndicator first and hide the list. Hide the indicator once you have reports and make lost visible.

<ActivityIndicator [busy]="isLoading" [visibility]="isLoading ? 'visible' : 'collapse'" row="2" horizontalAlignment="center"></ActivityIndicator>

4. Push data to temp array and once all items are pused, assign that temp array to reports.

_tempreports.push(new Report(data.reportid[i], data.report_name[i], data.report_status[i], data.report_value[i], status_text, status_class, data.report_justification));
this._reports = _tempreports;


来源:https://stackoverflow.com/questions/52629649/sharing-json-data-from-server-between-2-components

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!