来自Subject / Services的角度4/5组件变量不绑定到HTML模板 [英] Angular 4/5 Component variable from Subject/Services not binding to HTML template

查看:135
本文介绍了来自Subject / Services的角度4/5组件变量不绑定到HTML模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的app.component.ts文件中有一个变量,通过我的services.ts文件从控制器传入。

就我所见,通过Subject传递给Component的Object属性正在工作,因为我可以 console.log(this。 selectedContact.name),它将完全登录到控制台,这意味着它正确存储到变量 selectedContact:any; 中。但我似乎无法将其绑定到我的HTML,我很好奇我可能会丢失什么。



这是我试图绑定到的视图的app.component.ts文件:

 从'@ angular / core'导入{Component,OnInit}; 
从'../contacts-list/contacts-list.component'中导入{ContactsListComponent};
从'../api.service'中导入{ApiService};

@Component({
selector:'app-contact-details',
templateUrl:'./contact-details.component.html',
styleUrls: ['./contact-details.component.scss']
})
导出类ContactDetailsComponent实现OnInit {

selectedContact:any;

构造函数(private _apiService:ApiService){}
$ b ngOnInit(){this.showContact()}

showContact(){
this._apiService.newContactSubject.subscribe(
contact => {
this.selectedContact = contact;
console.log(this.selectedContact.name);
});




$ b这是我的HTML文件(我正在尝试的视图绑定:

 < div id ='contact-card'> 
< header>
<按钮routerLink ='/ home'><通讯录< /按钮>
< / header>
<部门ID =卡片容器>
< img id =largeContactPhotoonerror =onerror = null; src ='.. / assets / User Large / User - Large.png';
src = {{selectedContact.largeImageURL}} />
< h1> {{selectedContact.name}}< / h1>
< h2> {{selectedContact.companyName}}< / h2>
< ul>
< ; hr>
< li class =contact-data>
< h3>电话:< / h3>
{{selectedContact.phone.home}}
< hr>
< / li>
< li class =contact-data>
< h3>电话:< / h3>
{ {selectedContact.phone.mobile}}
< hr>
< / li>
< li class =contact-data>
< h3>电话:< / h3>
{{selectedContact.phone.work}}
< hr>
< / li>
< li class =contact-data>
< h3>地址:< / h3>
{{selectedContact.address.street}}< br>
{{selectedContact.address.city}},{{selectedContact.address.state}} {{selectedContact.address.zipcode}}
< hr>
< / li>
< li class =contact-data>
< h3>出生日期:< / h3>
{{selectedContact.birthdate}}
< hr>
< / li>
< li class =contact-data>
< h3>电子邮件地址:< / h3>
{{selectedContact.email}}
< hr>
< / li>
< / ul>
< / section>
< / div>

app.service.ts(其中点击事件数据传递给app.component.ts:

 从'@ angular / core'导入{Injectable}; 
从'@angular'导入{Http,Response} / http';
从'rxjs / Observable'导入{Observable};
从'rxjs / Subject'导入{Subject};
导入'rxjs / add / operator / map';

@Injectable()
export class ApiService {

// API URL
private url:string ='assets / api / contacts.json';

public newContactSubject = new Subject< any>();

//为请求
构造函数(private _http:Http){}
初始化HttpClient
//从REST API中提取JSON数据
getContacts():Observable< any> {
返回this._http.get(this.url)
.map((response:响应)=> response.json());
}
openSelectedContact(data){
this.newContactSubject.next(data);

}
}

同步组件这是点击事件发生的地方*

 从'@ angular / core'导入{Component,OnInit}; 
从'@ angular / router'导入{Router};
从'../api.service'中导入{ApiService};

@Component({
选择器:'app-contacts-list',
templateUrl:'./contacts-list.component.html',
styleUrls: ['./contacts-list.component.scss']
})
export class ContactsListComponent实现OnInit {
title:string ='Contacts';
sortedFavorites:any [] = [];
sortedContacts:any [] = [];
errorMessage:string;

构造函数(private _apiService:ApiService,private router:Router){}
$ b ngOnInit(){this.getContacts()}

getContacts ){
this._apiService.getContacts()
.subscribe(
(contacts)=> {

//按字母顺序排序JSON对象
contacts (a.name> b.name){return 1};
if(a.name< b.name){return - 1};
return 0;
})

//建立新的排序数组
contacts.forEach((item)=> {
if (item.isFavorite){
this.sortedFavorites.push(item);
} else {
this.sortedContacts.push(item);
}
}) ;
});
}

openFavorite($ event,i){< - 从HTML模板进来的点击事件
let selectedFavorite = this.sortedFavorites [i];
this._apiService.openSelectedContact(selectedFavorite); < - 将此数据路由到services.ts文件
this.router.navigate(['/ details']); <导航到详细视图以查看选定的联系人。
};






这个绑定可以和任何其他的测试变量一起使用,到我的app.component.ts文件中,并且它们被绑定到页面。我觉得这是正确的语法,它是正确绑定object.properties,但它似乎并没有工作。



我可能会缺少什么这个?编辑之一:我觉得我还应该补充说,这个完全相同的代码 是在我有过之前工作的时候 我的组件路由到这个组件。只有当我将文件移动到一个新组件并创建了一个不同的新组件时,才发生这种情况。也许它没有正确导入某处?



编辑二 :我重构了原始代码发布并更正了我的TypeScript声明,并从我的html模板中删除了 this 。我在 showContact()方法中放置了 console.log(this.selectedContact.name)函数,记录正确的名字,一旦联系人列表中的名称被点击并伴随着这个错误: ERROR TypeError:无法读取undefined 属性'largeImageURL'。所以它正确地记录 this.selectedContact.name ,并且该变量没有在我的应用程序的其他地方定义。我已经添加了我的app.service.ts文件以及我的兄弟组件.ts文件,以便将其放入发生点击事件的上下文中。我希望点击事件数据从Sibling组件 - > Api Service.ts文件 - >单击事件中的兄弟组件。这非常令人困惑,为什么这种情况没有发生。



编辑三
其他我注意到的问题是,每当我尝试使用安全导航操作符来解决此问题时,我的突出显示会在我的html模板中发生变化,使我认为它正在破坏它。





与此相比:





注意< / h1 >突出显示?这使得每个 开启和关闭标记都显示为灰色,而不是现在的红色。我从来没有试图使用安全的导航操作符,所以我不确定这是否正常。我已经在和{code>}} 周围使用了不同的空格,并且仍然没有运气。

解决方案

您是否期待数组或对象?您应该输入您从服务中获得的内容。
在这里你提到一个数组:

  selectedContact:any [] = []; 

在这里您提到一个对象。

 < H1> {{this.selectedContact.name}}< / h1> 

在模板中使用 json 管道。

  {{selectedContact | json}} 

这将帮助您调试。



此外,因为您的数据在您的服务收到之前会在浏览器中显示,您将收到未定义的变量。可以使用 * ngIf 。 (使用* ngIf,不要将您的selectedContact定义为一个数组)开始。

 < div id ='contact -card'* ngIf =selectedContact> 

 < H1> {{this.selectedContact?.name}}< / h1> 


I have a variable in my app.component.ts file that is passed in from a controller via my services.ts file.

As far as I can see, the Object property passed to the Component via the Subject is working, because I can console.log(this.selectedContact.name) and It will log to the console perfectly, which would mean that it is correctly being stored into the variable selectedContact: any;. But I cannot seem to bind this to my HTML and I am curious as to what I may be missing.

Here is my app.component.ts file for the view I'm attempting to bind to:

import { Component, OnInit } from '@angular/core';
import { ContactsListComponent } from '../contacts-list/contacts-list.component';
import { ApiService } from '../api.service';

@Component({
  selector: 'app-contact-details',
  templateUrl: './contact-details.component.html',
  styleUrls: ['./contact-details.component.scss']
})
export class ContactDetailsComponent  implements OnInit {

  selectedContact: any;

  constructor(private _apiService: ApiService) { }

  ngOnInit() { this.showContact()}

  showContact() {
    this._apiService.newContactSubject.subscribe(
      contact => {
         this.selectedContact = contact;
         console.log(this.selectedContact.name);
      });
  }
}

Here is my HTML file (The view I am attempting to bind to.:

<div id= 'contact-card' >
  <header>
  <button routerLink='/home'>< Contacts</button>
  </header>
  <section id= card-container>
    <img id ="largeContactPhoto" onerror="onerror=null;src='../assets/User Large/User — Large.png';"
         src={{selectedContact.largeImageURL}} />
    <h1> {{selectedContact.name}} </h1>
    <h2> {{selectedContact.companyName}} </h2>
    <ul>
      <hr>
      <li class="contact-data">
        <h3> Phone: </h3>
        {{selectedContact.phone.home}}
      <hr>
      </li>
      <li class="contact-data">
        <h3> Phone: </h3>
        {{selectedContact.phone.mobile}}
      <hr>
      </li>
      <li class="contact-data">
        <h3> Phone: </h3>
        {{selectedContact.phone.work}}
      <hr>
      </li>
      <li class="contact-data">
        <h3> Address: </h3>
        {{selectedContact.address.street}}<br>
        {{selectedContact.address.city}},{{selectedContact.address.state}} {{selectedContact.address.zipcode}}
      <hr>
      </li>
      <li class="contact-data">
        <h3> Birthdate: </h3>
        {{selectedContact.birthdate}}
      <hr>
      </li>
      <li class="contact-data">
        <h3> Email: </h3>
        {{selectedContact.email}}
      <hr>
      </li>
    </ul>
  </section>
</div>

app.service.ts (where the click event data is being passed to app.component.ts:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';

@Injectable()
export class ApiService {

  //API URL
  private url: string = 'assets/api/contacts.json';

  public newContactSubject = new Subject<any>();

  //Initialize HttpClient for request
  constructor(private _http: Http) { }

  //Pull JSON data from REST API
  getContacts(): Observable<any> {
    return this._http.get(this.url)
    .map((response: Response) => response.json());
  }
  openSelectedContact(data) {
  this.newContactSubject.next(data);

  }
}

Sibling Component THIS IS WHERE THE CLICK EVENT HAPPENS* :

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from '../api.service';

@Component({
  selector: 'app-contacts-list',
  templateUrl: './contacts-list.component.html',
  styleUrls: ['./contacts-list.component.scss']
})
export class ContactsListComponent implements OnInit {
  title : string = 'Contacts';
  sortedFavorites: any[] = [];
  sortedContacts: any[] = [];
  errorMessage: string;

  constructor (private _apiService: ApiService, private router: Router) {}

  ngOnInit(){ this.getContacts()}

  getContacts() {
     this._apiService.getContacts()
     .subscribe(
       (contacts) => {

        //Sort JSON Object Alphabetically
        contacts.sort((a , b) => {
          if (a.name > b.name) {return 1};
          if (a.name < b.name) {return -1};
          return 0;
        })

         //Build new Sorted Arrays
          contacts.forEach( (item) => {
           if (item.isFavorite) {
           this.sortedFavorites.push(item);
           } else {
           this.sortedContacts.push(item);
           }
         });
       });
     }

  openFavorite($event, i) { <--Click event coming in from HTML template
    let selectedFavorite = this.sortedFavorites[i];
      this._apiService.openSelectedContact(selectedFavorite); <--Routing this data to services.ts file
      this.router.navigate(['/details']); <--Navigate to detailed view to see selected contact.
  };

}

This binding will work with any other test variables that i put into my app.component.ts file and they get bounded to the page. I feel like this is the right syntax for it to be properly binding the object.properties, but it doesn't seem to be working.

What might I be missing on this? Thanks a lot in advance!!

EDIT One: I feel like I should also add that this exact same code was working before when I had my component routed to this component. It was only when I moved my files to a new component and created a different new that this started happening. Maybe it is isn’t imported correctly somewhere?

EDIT TWO: I have refactored the code in the original post and corrected my TypeScript declarations and removed this from my html template. I have placed my console.log(this.selectedContact.name) function inside my showContact() method and it does log the correct name once the name in the contacts list is clicked along side this error: ERROR TypeError: Cannot read property 'largeImageURL' of undefined. So it is logging this.selectedContact.name correctly and that variable isn't defined anywhere else in my application. I have added my app.service.ts file as well as my sibling component.ts file just to put this in context where the click event happens. I want the click event data to go from Sibling component --> Api Service.ts file --> Sibling component on a click event. This is very confusing to me why this isn't happening.

EDIT THREE One other issue that I have noticed is that whenever I attempt to use the safe navigation operator to resolve this, my highlighting changes in my html template, making me think that it is breaking it.

versus this:

Notice the change in the </h1> highlighting? This has subsiquently made every open and closing tag show up in grey instead of the red now. I have never attempted to use the safe navigation operator, so I am unsure as to whether this is normal. I have tried it with different spacing around the {{ and }} and still no luck.

解决方案

Are you expecting an array or an object? You should type exactly what you are getting from your service. Here you mention an array:

selectedContact: any[] = [];

Here you mention an object.

<h1> {{this.selectedContact.name}} </h1>

Give a shot in your template with the json pipe.

{{ selectedContact | json }}

This will help you debug.

Also, because your data is displayed on the browser before it is received by your service, you will get an undefined variable. Either use ? or an *ngIf. (With the *ngIf, don't define your selectedContact as an array to start with)

<div id= 'contact-card' *ngIf="selectedContact">

or

<h1> {{this.selectedContact?.name}} </h1>

这篇关于来自Subject / Services的角度4/5组件变量不绑定到HTML模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆