skip to Main Content

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 = [link as any];});

}

}


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 ?

3

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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 ''. 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';
    }
    
    Login or Signup to reply.
  3. 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: '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);
      }
    }
    

    Parent Component ts

    @Component({...})
    export class AppComponent {
      currentItem$!: Observable<string>;
    
      constructor(private myService: MyService) {}
    
      myFunction(): void {
        this.currentItem$ = this.myService.getData('foo');
      }
    }
    

    Parent providing a value to child component

    <button  class="nav-button" (click)='myFunction()'>Press me</button>
    
    <!-- make use of the async pipe to subscribe -->
    <app-info [item]="currentItem$ | async"></app-info>
    

    Child Component

    @Component({...})
    export class InfoComponent {
      @Input() item!: any; // I don'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 '@angular/core';
    
    @Component({
      ...,
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class InfoComponent implements OnChanges {
      @Input() item!: string;
      linkData!: any; // I don't know the data type so any....
    
      ngOnChanges(): void {
        this.http.get(this.linkUrl).subscribe(link => {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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search