问题
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
Subscribe in (loaded) mthod of RadListView.
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