API链接为什么在我使用Angular绑定在ngOnInit时不会更新?

huangapple go评论59阅读模式
英文:

Why won't API link update when I use angular binding in ngOnInit?

问题

The issue you're facing might be due to the asynchronous nature of HTTP requests. When you click the button to update currentItem, the HTTP request in ngOnInit of InfoComponent is triggered immediately, before currentItem is updated. To fix this, you can update the API URL inside the ngOnInit method whenever the item input changes. Here's how you can modify your InfoComponent:

import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-info',
  templateUrl: './info.component.html',
  styleUrls: ['./info.component.css']
})
export class InfoComponent implements OnInit, OnChanges {
  @Input() item = '';

  linkUrl = '';

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.updateLinkUrl();
    this.http.get(this.linkUrl).subscribe(link => {
      this.linkData = [link as any];
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.item) {
      this.updateLinkUrl();
    }
  }

  updateLinkUrl() {
    this.linkUrl = 'http://api.data/' + this.item + 'rest.of.api';
  }
}

By implementing OnChanges and watching for changes in the item input, you can update the linkUrl whenever the input changes, ensuring that the API URL is always up-to-date with the latest value of currentItem.

英文:

Hey I am trying to bind some data (onclick) .

I can tell the data binding is working because I have placed some interpolation in the HTML to display the new value. My issue is that I am trying to use that same data to update the string of an API.

The binding works but the string to the API never gets updated. Why is that so ?

Here is my Code

This is the component where the data is coming from.

HTML


<nav class="navbar nb" role="navigation" aria-label="main navigation" >
<button  class="nav-button" (click)='myFunction()'>button</button>
</nav>
<app-info [item]="currentItem"></app-info>

TS


import { Component, EventEmitter, Output, Input } from '@angular/core';
import { ValueService } from './value.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

myFunction() {this.currentItem = 'foo'; } 

currentItem = '';
}

This is the component where the data is passed to.


import { Component, EventEmitter, OnInit, Input, Output } from '@angular/core';
import {MatTabsModule} from '@angular/material/tabs';
import {MatListModule} from '@angular/material/list'; 
import { Observable } from 'rxjs';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import { size } from 'lodash';

@Component({
  selector: 'app-info',
  templateUrl: './info.component.html',
  styleUrls: ['./info.component.css']
})
export class InfoComponent implements OnInit {
@Input() item = ''; 

linkUrl = 'http//api.data'+this.item+'rest.of.api';

constructor(private http: HttpClient ) { }


ngOnInit(){
this.http.get(this.linkUrl).subscribe(link => {this.linkData = 
;}); } }

The Data Binding works when the link URL in ngOnInit is not a factor. I was expecting the link to be updated one the button was clicked.

How can I fix this issue ?

答案1

得分: 1

以下是翻译好的内容:

组件不应该注入HttpClient的依赖项,这应该由一个服务来处理。从您的代码来看,InfoComponent 是一个无状态组件,所以在这种情况下,AppComponent 应该提供linkData,例如:

服务

@Injectable({ providedIn: 'root' })
export class MyService {
  constructor(private http: HttpClient) {}
  
  getData(link: string): Observable<string> {
    const endpoint = `http//api.data${link}rest.of.api`;
    return this.http.get(endpoint);
  }
}

父组件 ts

@Component({...})
export class AppComponent {
  currentItem$!: Observable<string>;

  constructor(private myService: MyService) {}

  myFunction(): void {
    this.currentItem$ = this.myService.getData('foo');
  }
}

父组件向子组件提供值

<button class="nav-button" (click)='myFunction()'>Press me</button>

<!-- 使用异步管道来订阅 -->
<app-info [item]="currentItem$ | async"></app-info>

子组件

@Component({...})
export class InfoComponent {
  @Input() item!: any; // 我不知道这里应该有什么数据类型...
}

如果您确实希望采用您的方法,我建议您在InfoComponent 中进行以下更改:

import { ChangeDetectionStrategy } from '@angular/core';

@Component({
  ...,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class InfoComponent implements OnChanges {
  @Input() item!: string;
  linkData!: any; // 我不知道数据类型,所以用 any....

  ngOnChanges(): void {
    this.http.get(this.linkUrl).subscribe(link => { this.linkData = [link as any]; });
  }
}

每当item更改时,ngOnChanges 将检测到并触发必要的逻辑,因此建议将更改检测设置为onPush

有关在组件之间共享数据的更多信息,请阅读官方文档

英文:

Components shouldn't have the HttpClient dependency injected, that should be handled with a service. Looking at your code, it looks like InfoComponent is a dumb component, so the parent component, in this case, AppComponent should be the one providing the linkData, for example:

Service

@Injectable({ providedIn: &#39;root&#39;})
export class MyService {
  constructor(private http: HttpClient) {}
  
  getData(link: string): Observable&lt;string&gt; {
    const endpoint = `http//api.data${link}rest.of.api`;
    return this.http.get(endpoint);
  }
}

Parent Component ts

@Component({...})
export class AppComponent {
  currentItem$!: Observable&lt;string&gt;;

  constructor(private myService: MyService) {}

  myFunction(): void {
    this.currentItem$ = this.myService.getData(&#39;foo&#39;);
  }
}

Parent providing a value to child component

&lt;button  class=&quot;nav-button&quot; (click)=&#39;myFunction()&#39;&gt;Press me&lt;/button&gt;

&lt;!-- make use of the async pipe to subscribe --&gt;
&lt;app-info [item]=&quot;currentItem$ | async&quot;&gt;&lt;/app-info&gt;

Child Component

@Component({...})
export class InfoComponent {
  @Input() item!: any; // I don&#39;t know what type of data should be here...
}

If you really want to go with your approach, I suggest you do the following changes just in your InfoComponent:

import { ChangeDetectionStrategy } from &#39;@angular/core&#39;;

@Component({
  ...,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class InfoComponent implements OnChanges {
  @Input() item!: string;
  linkData!: any; // I don&#39;t know the data type so any....

  ngOnChanges(): void {
    this.http.get(this.linkUrl).subscribe(link =&gt; {this.linkData = [link as any];});
  }
}

Every time item is changed, ngOnChanges will detect that, and trigger the necessary logic, for this, it is recommended to change the change detection to onPush.

For more information about sharing data between components, I recommend reading the official docs

答案2

得分: 0

In your InfoComponent, you are setting the value of linkUrl when the component is being instantiated, so linkUrl is built using the available value for item, which at that moment is ''. Since linkUrl is just a string, there is no way it will update after item is updated. You can use a function or a getter that takes the value of item and builds the linkUrl for you, something like:

get linkUrl() {
    return 'http://api.data' + this.item + 'rest.of.api';
}
// or
linkUrl() {
    return 'http://api.data' + this.item + 'rest.of.api';
}
英文:

In your InfoComponent you are setting the value of linkUrl when the component is being instanciated, so linkUrl is build using the available value for item, which at that moment is &#39;&#39;. Since linkUrl is just a string, there is no way it will update after item is updated.
You can use a function or a getter that takes the value of item and builds the linkUrl for you, something like:

get linkUrl() {
    return &#39;http//api.data&#39;+this.item+&#39;rest.of.api&#39;;
}
// or
linkUrl() {
    return &#39;http//api.data&#39;+this.item+&#39;rest.of.api&#39;;
}

答案3

得分: 0

我弄清楚了问题。根据@Johnalternate的说法,linkUrl是一个字符串,对该字符串的更改需要进行更新。 ngOnInit在组件的首次加载和后续加载时都会触发。如果一切都是静态的,更新不会进行。

所以最好的方法是使用一个不同的生命周期钩子叫做OnChanges()。使用这个钩子,所有似乎都会在点击按钮时更新。

英文:

I figured the issue. As stated by @Johnalternate the linkUrl is a string and changes to that string needs to be update. ngOnInit fires on first and subsequent loads of the component. If all is already static the update won't go through.

So the best bet was to use a different lifecycle hook called OnChanges() . With that hook all seems to update on the click of a button.

huangapple
  • 本文由 发表于 2023年5月17日 22:44:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76273363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定