n00b question: concatenating string using 2 way binding

49 views
Skip to first unread message

Rich Leach

unread,
Nov 6, 2017, 8:13:10 PM11/6/17
to Angular and AngularJS discussion
Hi

I'm trying to build a string from a form that I will ultimately pass as a url for a service call. 

I have a hard coded string, something like 'https://api.iextrading.com/1.0/stock/IBM/quote'

... where "IBM" will be dynamically updated with the user entered value. 

So in my html template I have 
<input type="text" class="form-control" [(ngModel)]="tickersymbol">
      <div>
      </div>

...which outputs my desired string to the screen. 

Like I said, n00b question, but how/where would I capture the value from the form field and then pass it to my service?

Thanks in advance,

Rich

Zlatko Đurić

unread,
Nov 7, 2017, 3:11:03 AM11/7/17
to Angular and AngularJS discussion
If it's a template-driven form, your component would have a property named that.

E.g. 

export class MyComponent {
  tickersymbol
:string;
 
// later in the code...
  getQuote
() {
   
this.myService.getQuote(this.tickerSymbol).subscribe(....);
 
}
}

Arnaud Deman

unread,
Nov 7, 2017, 3:15:35 AM11/7/17
to Angular and AngularJS discussion

Hello Rich,

I am not an angular expert but I think your template is correct.

In the associated component you just need something like :
@Input() tikersymbol: string;

As you use two way binding the value will be updated when the user enter a value.
Here is the angular doc : https://angular.io/guide/template-syntax#two-way-binding---

Regards,
Arnaud.

Zlatko Đurić

unread,
Nov 7, 2017, 3:25:22 AM11/7/17
to Angular and AngularJS discussion
Hey Arnaud,


On 07.11.2017 09:15, Arnaud Deman wrote:


In the associated component you just need something like :
@Input() tikersymbol: string;

As you use two way binding the value will be updated when the user enter a value.
Here is the angular doc : https://angular.io/guide/template-syntax#two-way-binding---


You don't need @Input() there. Input annotation is required when you expect that this component will get input from it's parent component, not from the template itself. In this case, a simple tickersymbol: string; will bind the value in the form template to the value on the component.

It would still work with Input, but it's creating extra bindings. Input gives you the ability to do something like this:

@Component({
  selector
: 'my-cmp',
 
...
})
export class MyCmp {
 
@Input() tickerSymbol:string;
}


// another component which users MyCmp
@Component({
  selector
: 'parent-cmp',
 
template: `
<p>This is the parent template using MyCmp as child component.
It gives it "tickerSymbol" as input.
</p>

<my-cmp [tickerSymbol]="'IBM'"></my-cmp>



Like I've said, this still works in the particular case, but the `tickerSymbol` on component where it's been annotated with @Input would change not only when the form value changes, but also when the value changes on the parent. It's used for different purposes.

Arnaud Deman

unread,
Nov 7, 2017, 4:18:27 AM11/7/17
to Angular and AngularJS discussion
Hi Zlatko,

Yes you are right,
my english is not very strong and I missed that in the docs !

Thanks,
Arnaud.

Rich Leach

unread,
Nov 7, 2017, 12:55:58 PM11/7/17
to Angular and AngularJS discussion
Thank you for your help!

I think the larger question is, how do I actually parse, and pass, the string (that will represent the actual URL to my web service) from my .html form and into my .ts component (to ultimately inject into the service)?

I've been targeting the strategy of trying to combine the 2 strings (tickersymbolfront is always static, tickersymbolback is where the form value from the user gets appended) and then pass that combined value to the method (in the service). I get the feeling I'm doing something silly where I'm not able to join the strings correctly and/or incorrectly passing them to the method....


SNIPPETS:

.HTML

<button class="btn btn-primary" (click)="onGetStock()">Get Stock</button>

<input type="text" class="form-control" [(ngModel)]="tickersymbol">



.TS

...

export class AppComponent {
  tickersymbolfront:string = 'https://api.iextrading.com/1.0/stock/';
  tickersymbolback:string = '{‌{tickersymbol}}'&&'/quote';
  apicall={‌{tickersymbolfront}}+{‌{tickersymbolback}};  

...

  onGetStock(apicall) {
    this.serverService.getStock()
      .subscribe(
        (data: any[]) => console.log(data),
        (error) => console.log(error)
      );
  }



SERVICE.TS

...

  getStock() {
    return this.http.get('https://api.iextrading.com/1.0/stock/TTD/quote')  //this will get updated with the parsed string from the user submitted value
    .map(
      (response:Response) => {
        const data = response.json();
        return data;
      }
    );
  }



Again, thanks for your help.

Rich

Arnaud Deman

unread,
Nov 7, 2017, 4:57:08 PM11/7/17
to Angular and AngularJS discussion
Hi,

I try  again ;)

I think the interpolation i.e. : '{‌{tickersymbol}}'  can be used in the template not in the component.
In the component you could use this kind of string :
let apicall: string=`https://api.iextrading.com/1.0/stock/${tickersymbol}&&/quote`;
(note the quote used: `)

And then pass it to the injected service.

Hope this will help !
Regards,
Arnaud.

Lucas Lacroix

unread,
Nov 7, 2017, 5:13:43 PM11/7/17
to ang...@googlegroups.com
You've bound your input element to the "tickersymbol" variable. Angular will make sure that when the user modifies the input that the member variable on the instance of the component will also be updated.

So, here is what you can do:

component.TS
// Note: remove tickersymbolback and tickersymbolfront
// need to declare the member variable or you will get a compile error
tickersymbol: string;
onGetStock() {
    this.serverService.getStock(this.tickersymbol)

      .subscribe(
        (data: any[]) => console.log(data),
        (error) => console.log(error)
      ); 
  }


Service.ts
getStock(symbol: string) {
    return this.http.get(`https://api.iextrading.com/1.0/stock/${encodeURIComponent(symbol)}/quote`)  //this will get updated with the parsed string from the user submitted value

    .map(
      (response:Response) => {
        const data = response.json();
        return data;
      }
    ); 


`` is string interpolation and ${} is the replacement string. So, if the symbol the user typed in was "DEMO", the resulting URL would be: "https://api.iextrading.com/1.0/stock/DEMO/quote".

--
You received this message because you are subscribed to the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at https://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.
--
Lucas Lacroix
Computer Scientist
Advanced Technology Division, MEDITECH

Rich Leach

unread,
Nov 7, 2017, 7:34:55 PM11/7/17
to Angular and AngularJS discussion
Thank you! This is so helpful as I learn Angular....

Everything is now working except for when I want to print the results to the screen instead of just logging to the console.... I made the following changes to the app.component.ts file:
  onGetStock() {
    this.serverService.getStock(this.tickersymbol)
      .subscribe(
        (data: any[]) => this.data = data, // this was set to console.log() but I'm trying to get it to output to the screen.
        (error) => console.log(error)
      );
      this.quoteReturned = true;
  }

... and here in my app.component.html I'm trying to get the results to display:
     <div *ngIf="quoteReturned">
        QUOTE RETURNED:   {{ data.companyname }}
      </div>

but this generates an error saying "... companyname is undefined...." even though companyname was one of the elements in the returned array object that was printed to the console. 

How do I gain access to the results from the service call on screen? I had it in the console....

Thank you again,

Rich

Zlatko Đurić

unread,
Nov 7, 2017, 7:43:24 PM11/7/17
to ang...@googlegroups.com
Well, if it's aan array, you will have to do something like dara[0].companyName.

What does your json look like?

Also, use data?.companyName in the template, so that it doesn't break if your data is undefined, like when you're getting the quote.


You received this message because you are subscribed to a topic in the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/nmbleJuxqvI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+unsubscribe@googlegroups.com.

Rich Leach

unread,
Nov 7, 2017, 8:07:43 PM11/7/17
to Angular and AngularJS discussion
LOL

... you would think this would be something easy.... 

{{data[0].companyName}} is not working, nothing gets returned (no errors either).

I've included the returned json below (copied directly from the console). In my service call I'm actually calling "... response.json()" so I'm not sure why this isn't rendering to the screen. I even tried 

<div *ngFor="let d of data">
    QUOTE RETURNED:   {{data[0].companyName}}
</div>

... no dice. Any ideas? 
  1. {symbol"MSFT"companyName"Microsoft Corporation"primaryExchange"Nasdaq Global Select"sector""calculationPrice"close", …}
    1. avgTotalVolume:19953190
    2. calculationPrice:"close"
    3. change:-0.2
    4. changePercent:-0.00237
    5. close:84.27
    6. closeTime:1510088400240
    7. companyName:"Microsoft Corporation"
    8. delayedPrice:84.08
    9. delayedPriceTime:1510091860473
    10. iexAskPrice:0
    11. iexAskSize:0
    12. iexBidPrice:0
    13. iexBidSize:0
    14. iexLastUpdated:1510088399455
    15. iexMarketPercent:0.03412
    16. iexRealtimePrice:84.215
    17. iexRealtimeSize:100
    18. iexVolume:611621
    19. latestPrice:84.27
    20. latestSource:"Close"
    21. latestTime:"November 7, 2017"
    22. latestUpdate:1510088400240
    23. latestVolume:17925586
    24. marketCap:650108515733
    25. open:84.81
    26. openTime:1510065000721
    27. peRatio:28
    28. previousClose:84.47
    29. primaryExchange:"Nasdaq Global Select"
    30. sector:""
    31. symbol:"MSFT"
    32. week52High:86.2
    33. week52Low:57.28
    34. ytdChange:0.34979226589964846
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

Zlatko Đurić

unread,
Nov 8, 2017, 3:22:43 AM11/8/17
to Angular and AngularJS discussion


On Wednesday, November 8, 2017 at 2:07:43 AM UTC+1, Rich Leach wrote:
LOL

... you would think this would be something easy.... 

{{data[0].companyName}} is not working, nothing gets returned (no errors either).

I've included the returned json below (copied directly from the console). In my service call I'm actually calling "... response.json()" so I'm not sure why this isn't rendering to the screen. I even tried 

<div *ngFor="let d of data">
    QUOTE RETURNED:   {{data[0].companyName}}
</div>

... no dice. Any ideas? 


Well, your code is probably buggy. Here, the "quote getter" works just fine: 


Take a look and see what you did differently.
 

Rich Leach

unread,
Nov 8, 2017, 9:11:18 AM11/8/17
to Angular and AngularJS discussion
So clearly there's something in the way I'm trying to display my code that's not working, as I've tried displaying the data  {{data.companyName}} simply didn't work for me, I'll review that and find the err of my ways....

<section *ngIf="data" class="data">
<h2>Results</h2>
<p>{{ data.companyName }}</p>
<pre> {{ data | json }}</pre>
</section>

I can see I have some homework to do with pipes especially, as this would have been handy to use in my debugging ( your line of code: ... {{ data | json }}... ). For memorialization purposes the Angular docs even suggest using JSON pipe for debugging purposes: 


The JsonPipe provides an easy way to diagnosis a mysteriously failing data binding or inspect an object for future binding.

I'm going to go ahead and consider this thread closed, even though I still have to finalize exactly how I'll get my quote displayed and output into my UI. 

Thanks again for all of your help, you're making the learning process much more effective.

Rich
Reply all
Reply to author
Forward
0 new messages