Coding

Angular 2 Full App Tutorial – Weather App – #10 Observable Power

  • 00:00:00 welcome back to the next part of this
  • 00:00:03 weather app series we're nearing the end
  • 00:00:06 of the series and reason course is that
  • 00:00:09 this application already works really
  • 00:00:12 great however there are a couple of
  • 00:00:14 things I want to fix what I want to add
  • 00:00:17 let's put it that way for one I will get
  • 00:00:20 rid of this dummy data as we are now
  • 00:00:22 able to add our own data second I want
  • 00:00:26 to have a sidebar which allows us to
  • 00:00:28 store separate profiles containing
  • 00:00:33 different cities which we then can load
  • 00:00:34 Q well changed cities we see here
  • 00:00:38 because once I got rid of the dummy data
  • 00:00:40 here this will be empty by default and
  • 00:00:42 only be full of the data we add here but
  • 00:00:45 in a real application you might want to
  • 00:00:46 save that and one step is to save it on
  • 00:00:49 the front and a different profiles
  • 00:00:50 however on a real app of course you
  • 00:00:53 would synched it with some kind of
  • 00:00:54 server where these profiles would be
  • 00:00:56 stored too so I will first start by
  • 00:00:58 getting rid of this dummy data and those
  • 00:01:01 of course happens at the Beverly ETS
  • 00:01:03 file where I just delete the two new
  • 00:01:05 Webber items which are added by default
  • 00:01:08 so that we only have an empty array left
  • 00:01:11 so that's one thing and now if we have a
  • 00:01:14 look at the application
  • 00:01:15 I can still add Berlin and this looks
  • 00:01:19 good but as I said it would be great to
  • 00:01:21 save it in a kind of profile on the left
  • 00:01:24 here maybe I also have a default profile
  • 00:01:26 at startup of the application which you
  • 00:01:28 could always note so in order to do this
  • 00:01:31 I will create a new file here and I'm
  • 00:01:35 doesn't the root development folder I
  • 00:01:37 will call this fall profile oops
  • 00:01:41 create a new fall profile dot yes and
  • 00:01:45 this much just you find the profile
  • 00:01:47 class I want to have profile now I want
  • 00:01:54 my profile class to have
  • 00:01:58 our name so each profile should have a
  • 00:02:01 name profile name which is of course a
  • 00:02:03 string and also each profile should have
  • 00:02:06 an array of cities which will be an
  • 00:02:09 array of strings so this will not be an
  • 00:02:13 array of Weber items but because we
  • 00:02:16 won't store the complete fetch to ever
  • 00:02:19 item here but instead I will just store
  • 00:02:22 the city names strings here which will
  • 00:02:25 be searched for in the API
  • 00:02:28 once I load a profile because of course
  • 00:02:30 I always want to have the most recent
  • 00:02:31 Weber data therefore I'm not saving the
  • 00:02:33 Weber data but just the city names which
  • 00:02:35 I want to search on the open Weber metal
  • 00:02:38 open weather map comm API so with this
  • 00:02:41 I'm able to store a list of cities
  • 00:02:44 basically that's all and that's the
  • 00:02:46 profile class I'll use next I want to
  • 00:02:49 create this sidebar component which will
  • 00:02:52 hold all these profiles so also in the
  • 00:02:55 dev folder I will treat a new file
  • 00:02:56 called site oops
  • 00:03:00 cold site bar component TS and of course
  • 00:03:06 this will start by being exported so an
  • 00:03:08 exported class called sidebar sidebar
  • 00:03:12 component and I will add the component
  • 00:03:16 decorator of course this will receive a
  • 00:03:20 selector of my sidebar and of course
  • 00:03:26 also a template now what should be
  • 00:03:29 inside this template well I want to have
  • 00:03:32 let's say a heading which says save
  • 00:03:35 profile something like this and then I
  • 00:03:40 will have a button which allows me to
  • 00:03:42 save a new fault profile so safe list
  • 00:03:45 profile should save to current list of
  • 00:03:48 weather items so of the you ever items
  • 00:03:51 we will have down here for example
  • 00:03:53 Berlin will save the current list as a
  • 00:03:55 new profile so this button therefore
  • 00:03:59 it's a click listener which should fire
  • 00:04:02 the or target the unsaved new method
  • 00:04:05 which I will have to create in the body
  • 00:04:06 of this component of course so this
  • 00:04:09 allows me to create
  • 00:04:10 new profile next I will add an article
  • 00:04:14 so default html5 element here which
  • 00:04:18 should basically hold my different
  • 00:04:21 profiles or hold one profile I will
  • 00:04:23 later on loop through all these profiles
  • 00:04:25 of course each article will have its a
  • 00:04:29 heading age 4 with the name of the
  • 00:04:32 profile profile name and the city name
  • 00:04:37 city or the name of all cities excuse me
  • 00:04:40 might be multiple cities like New York
  • 00:04:43 London I also want to add a button in
  • 00:04:47 let's say top right corner which allows
  • 00:04:49 me to delete a profile therefore I will
  • 00:04:52 use just a X so the X character and I
  • 00:04:58 will give this a class of delete which I
  • 00:04:59 will have to write my own my own to give
  • 00:05:02 this a styling I want to have and I will
  • 00:05:04 add a click listener here to which
  • 00:05:07 should be on the lead profile profile
  • 00:05:11 and I want to get the event the click
  • 00:05:14 event passed into this method so that I
  • 00:05:16 can stop propagation later on so that it
  • 00:05:19 doesn't bubble up any more though but I
  • 00:05:21 can stop it so that is only the click
  • 00:05:24 event on this profile is recognized
  • 00:05:26 so let's have a look at this and let's
  • 00:05:29 see home ok how this looks in our view
  • 00:05:31 in our template in order to see this I
  • 00:05:34 will of course have to embed my sight
  • 00:05:36 bar here in the app component so I will
  • 00:05:38 do this right below my header my sidebar
  • 00:05:42 and also of course I need to add here my
  • 00:05:45 director Cerie so a sidebar component
  • 00:05:48 and of course as always make sure to add
  • 00:05:51 the import to the sidebar component now
  • 00:05:54 if we reload the page well we can see
  • 00:05:58 this doesn't look too pretty to be
  • 00:05:59 honest so that definitely needs some
  • 00:06:01 styling now in the source code of this
  • 00:06:04 project and you can find us on github
  • 00:06:06 I will provide this sidebar dot s CSS
  • 00:06:10 file which has all the styling I need to
  • 00:06:14 make this look better so you may just
  • 00:06:17 toss this into your project then or
  • 00:06:21 positive window right now and then let
  • 00:06:25 it go again and pause now and resume and
  • 00:06:30 pause to type it whatever you prefer but
  • 00:06:35 as I said you will find it like it hub
  • 00:06:37 repository now in order to apply these
  • 00:06:39 styles to this component though I will
  • 00:06:42 need to add something to this component
  • 00:06:45 decorator the style URLs metadata which
  • 00:06:49 allows me to specify an array of strings
  • 00:06:54 referring to paths in my project which
  • 00:06:57 holds CSS files so I only want to add
  • 00:07:02 specify one string here and this will be
  • 00:07:04 the path to my sidebar dot CSS file this
  • 00:07:08 will live in the source CSS folder and
  • 00:07:10 then sidebar dot CSS since this is the
  • 00:07:14 folder where all my a CSS files will get
  • 00:07:17 compiled to and remember that when
  • 00:07:21 accessing style or template URL sangla –
  • 00:07:24 you always have to think from the root
  • 00:07:27 folder the project folder on and not
  • 00:07:31 from the file where you're currently in
  • 00:07:33 so source slashed CSS refers to this
  • 00:07:37 folder even though this def folder were
  • 00:07:41 a side part of component lesson has no
  • 00:07:44 source folder in it this has to be seen
  • 00:07:47 from the project route on very important
  • 00:07:50 now the style is imported here well only
  • 00:07:54 be applied to this component that's
  • 00:07:56 important to only this component will
  • 00:07:59 receive the styles and after if you have
  • 00:08:01 a look inside part of a CSS file you see
  • 00:08:05 that host selector and this means the
  • 00:08:09 whole body but only of that component
  • 00:08:12 should receive these styles here and
  • 00:08:16 that is a good way to make sure that
  • 00:08:19 you're not over writing or interfering
  • 00:08:22 with some other styling your application
  • 00:08:24 but instead only apply your styles where
  • 00:08:26 you want them to be applied to go a
  • 00:08:29 little bit deeper into that that uses
  • 00:08:31 you encapsulation a concept
  • 00:08:34 introduce Bangala – which kind of in a
  • 00:08:38 default setting at least resembles –
  • 00:08:41 shadow Dom specification which is not
  • 00:08:44 supportable browsers and shadow Dom
  • 00:08:46 would mean that each element in your Dom
  • 00:08:49 might have will a shadow Dom a separate
  • 00:08:53 Dom behind it with its own styles and so
  • 00:08:56 on and as I said this is not support
  • 00:08:58 about browsers but angular to emulate
  • 00:09:02 stays by default such that it through a
  • 00:09:05 clever trick by appending an attribute
  • 00:09:08 to your element and then adding this
  • 00:09:10 attribute to all the styles which should
  • 00:09:12 only be applied to this element side
  • 00:09:15 note so by using this technique it
  • 00:09:17 emulates these component or element
  • 00:09:21 specific styles and make sure that if
  • 00:09:24 you style for example the age the
  • 00:09:27 element here only the h3 element in this
  • 00:09:30 component that receives the style and at
  • 00:09:33 all and not all HV elements in your
  • 00:09:35 application if you want to learn more
  • 00:09:38 about you encapsulation you will find a
  • 00:09:40 link in the description below so what is
  • 00:09:43 if I now reload this looks much nicer
  • 00:09:49 but to make it look really nice I will
Coding

Angular 2 Full App Tutorial – Weather App – #10 Observable Power

  • 00:00:00 so this is how we left our web app and
  • 00:00:03 now I want to change it in a way that it
  • 00:00:06 automatically starts looking when we
  • 00:00:09 type so how could we implement this
  • 00:00:14 behavior with observables it's to be
  • 00:00:18 honest not really that hard we would
  • 00:00:21 start here in our Webber search
  • 00:00:23 component and of course here I want cube
  • 00:00:27 listen to all changes in on this input
  • 00:00:31 element here so I will add such a such
  • 00:00:35 an event listener and input is the
  • 00:00:38 method or the event and looking for this
  • 00:00:40 will fire whenever will I type something
  • 00:00:43 into this field I then want to call a
  • 00:00:45 method let's call it on search location
  • 00:00:49 and I want to pass the current value of
  • 00:00:52 this input field therefore I will gift
  • 00:00:55 us a local variable called input and
  • 00:00:58 then I can just pass input dot value and
  • 00:01:02 with this on every keystroke I will
  • 00:01:05 trigger this method here and I will pass
  • 00:01:07 the current value of this input field
  • 00:01:10 now I'll let me next so add this method
  • 00:01:14 here this on search location which will
  • 00:01:20 get the city name as an input because I
  • 00:01:23 will get a string the input of there or
  • 00:01:25 the value of this input field and I know
  • 00:01:27 that this input field is there to search
  • 00:01:30 for a city that's why I called the
  • 00:01:32 variable here city name now I could add
  • 00:01:36 this code here and let's see what then
  • 00:01:40 happens here of course I would replace
  • 00:01:45 this with just city names and were
  • 00:01:47 directly getting this information and
  • 00:01:51 now let's see what happens as I type it
  • 00:01:56 added a couple of cities which I don't
  • 00:02:00 know why this match Berlin at any point
  • 00:02:04 Teegarden is in Berlin so this is okay
  • 00:02:07 but yeah if it's just on every key type
  • 00:02:11 it triggers this API and
  • 00:02:14 for the city the problem with this is
  • 00:02:17 not only that we spam our API and by the
  • 00:02:20 way on a blogger map there is a limit on
  • 00:02:23 requests per minute I think so we spam
  • 00:02:26 this API this is bad and we get a couple
  • 00:02:30 of well cities we don't really want here
  • 00:02:33 we don't want to add them right away
  • 00:02:34 and it would be better to yeah we would
  • 00:02:37 just want to see some suggestions here
  • 00:02:39 and then add the one we want
  • 00:02:42 however these chester's should also not
  • 00:02:44 update with every keystroke but only
  • 00:02:47 let's say after every every keystroke
  • 00:02:50 that actually changed the word and only
  • 00:02:54 all let's say every 300 milliseconds so
  • 00:02:58 that the user actually has to pause for
  • 00:03:00 a short period before we send out a
  • 00:03:02 request so that while worker typing
  • 00:03:05 Berlin were waiting for the user to
  • 00:03:07 finish typing before querying for B for
  • 00:03:10 b efore BER and so on now this sounds
  • 00:03:15 very complicated but the great thing is
  • 00:03:17 with observable it's easy to implement
  • 00:03:21 however we low need to change the way we
  • 00:03:26 use this component or how we work here I
  • 00:03:30 will get rid of this logic here because
  • 00:03:33 this is not what we will be doing here
  • 00:03:35 instead what I want is I want a separate
  • 00:03:39 observable stream separate observable so
  • 00:03:43 to say for which I personally can create
  • 00:03:47 events and fire them and I define when
  • 00:03:50 they are fired all 300 milliseconds for
  • 00:03:53 example and then this stream will I will
  • 00:03:57 also listen to it whenever I fulfill
  • 00:04:01 these requirements reach out to the HTTP
  • 00:04:04 service and fire this or send this
  • 00:04:08 request and listen to this response in
  • 00:04:11 order to do this I need some kind of
  • 00:04:13 object which I can both listen to
  • 00:04:15 because I want to listen for the user to
  • 00:04:18 pause typing but I once also want to
  • 00:04:21 fire you but I want to emit events
  • 00:04:24 because I want to emit do you
  • 00:04:26 are just typed and the observable
  • 00:04:30 library rxjs
  • 00:04:31 offers such and such an object a subject
  • 00:04:35 this is an observer and an observable at
  • 00:04:39 the same time so I will create such an
  • 00:04:42 subject here and we'll call it search
  • 00:04:44 stream and this will be a new subject
  • 00:04:47 and subject has to be imported from rxjs
  • 00:04:51 subject it will be off type string and
  • 00:04:59 now what do I do with the subject on
  • 00:05:02 each type here on each time I type into
  • 00:05:06 this input field I will use the search
  • 00:05:09 stream and I will call the next method
  • 00:05:12 and omit the city name which was entered
  • 00:05:15 and this basically means it will trigger
  • 00:05:18 upon each keystroke it will emit this
  • 00:05:21 value to the subject and now I have to
  • 00:05:24 configure the subject in a way that it
  • 00:05:27 will ignore a lot of these he wins until
  • 00:05:31 a certain set of conditions is met for
  • 00:05:33 example 300 Melissa consent since the
  • 00:05:37 last hit or since the last he went I
  • 00:05:39 will do this in yuan init method and
  • 00:05:42 therefore I will implement on in it in
  • 00:05:45 my class here and then here implement
  • 00:05:49 you ng on init method and in this method
  • 00:05:52 what I will do is I will use my search
  • 00:05:54 stream and now I could subscribe to it
  • 00:05:57 to listen to all these input changes and
  • 00:06:00 I will do this first to show how this
  • 00:06:02 works I will get back some data and what
  • 00:06:06 what data would we get back well
  • 00:06:10 probably the value T user entered so
  • 00:06:14 let's Lock this data to confirm this now
  • 00:06:19 if I type something here you can see in
  • 00:06:23 the console I'm getting my interest here
  • 00:06:26 and this is because while on each
  • 00:06:28 keystroke I omit the current value and
  • 00:06:31 here I set up well a listener now this
  • 00:06:34 is almost what I want but not quite
  • 00:06:37 I want to take this value and send it
  • 00:06:42 out to the API and use it there I want
  • 00:06:46 to call well whatever I'm currently
  • 00:06:49 doing here in on submit I want to call
  • 00:06:52 it here queue but with this value now a
  • 00:06:56 good way to do this is I can use the
  • 00:07:00 switch map operator on this observable
  • 00:07:04 and watch what switch map does is it
  • 00:07:08 allows me to map one stream one
  • 00:07:12 observable into an average and I'll best
  • 00:07:14 show this with an example here so what I
  • 00:07:17 will do is I will have my like by a my
  • 00:07:21 my input which is a string and I'm using
  • 00:07:24 a fat arrow function here of course
  • 00:07:26 again and then I will call the weather
  • 00:07:29 service search Weber data method on this
  • 00:07:34 term and this will indeed also or on
  • 00:07:38 this input excuse me and this will
  • 00:07:41 subscribe to it and down here data will
  • 00:07:46 be something different let's see what is
  • 00:07:49 data now if I type Berlin you can see
  • 00:07:53 now we're getting back however data
  • 00:07:55 object because we're transforming our
  • 00:07:58 observable so to say we're saying use
  • 00:08:01 the input we're emitting on each
  • 00:08:04 keystroke but don't map this into the
  • 00:08:08 data you use here instead map it into a
  • 00:08:12 new observable where you pass this value
  • 00:08:15 and then the new data the new response
  • 00:08:18 of this overall observables Freeman
  • 00:08:22 should be the response of this
  • 00:08:25 observable this is the translation you
  • 00:08:29 could give to you to this operator to
  • 00:08:31 the switch map operator and with this
  • 00:08:34 we're now on each keystroke searching
  • 00:08:37 for this city now we're almost there
  • 00:08:40 because well with this we could achieve
  • 00:08:44 what we want and we could update but we
  • 00:08:47 would do this on each keystroke but to
  • 00:08:50 begin with
  • 00:08:51 let's do this I therefore will add a new
  • 00:08:57 field here called theta which will be of
  • 00:09:00 type an E and an empty object at the
  • 00:09:02 beginning I will then here set this data
  • 00:09:08 field equal to the data we get back here
  • 00:09:11 and then I can in my template output
  • 00:09:16 city found and then here I will output
  • 00:09:23 data name to output the city name so
  • 00:09:28 let's try it again
  • 00:09:29 Berlin as you can see it updated it
  • 00:09:33 looks pretty good but still we're
  • 00:09:35 spamming the API and well we will reach
  • 00:09:39 our limit sometimes and then we'll have
  • 00:09:41 to wait for a minute and generally this
  • 00:09:43 is not the best style because these are
  • 00:09:45 a lot of unnecessary HTTP requests how
  • 00:09:50 to what can we do to reduce the number
  • 00:09:52 of HTTP requests it is really simple we
  • 00:09:55 add exactly two new operators to our
  • 00:09:59 observable string here before we switch
  • 00:10:02 our observable stream and before we call
  • 00:10:06 this new observable and make this
  • 00:10:08 request I want to for one gift us a
  • 00:10:13 debounce time of 300 this is
  • 00:10:17 milliseconds here as an argument and
  • 00:10:19 debounce time operator means or this
  • 00:10:23 debones time operated does that we will
  • 00:10:27 only react to events which are at least
  • 00:10:31 300 milliseconds after the last event
  • 00:10:34 received
  • 00:10:35 so here were emitting events on each
  • 00:10:37 type but we will ignore all of them
  • 00:10:40 until 300 milliseconds have passed and
  • 00:10:43 then we will use the last event we got
  • 00:10:46 so once we finish typing and 300
  • 00:10:49 milliseconds have passed we will use the
  • 00:10:51 very last and only this result that we
  • 00:10:54 got now this would be great but we would
  • 00:11:00 still send multiple requests in case
  • 00:11:02 that let's say we type then
  • 00:11:04 we accidentally press a wrong button or
  • 00:11:07 wrong key and we Angeles but we leave
  • 00:11:11 some time but windows and therefore in
  • 00:11:14 fury we would have 300 milliseconds
  • 00:11:17 between it but the actual value has not
  • 00:11:20 changed in order to react to this case
  • 00:11:24 I'll add another operator this tank
  • 00:11:27 anthill changed and this takes no
  • 00:11:29 argument here and this simply means only
  • 00:11:33 use this event you received here an
  • 00:11:36 event of course is this new value
  • 00:11:39 entered into this input if it is
  • 00:11:42 different to the last event and what
  • 00:11:45 this were safe we're waiting for 300
  • 00:11:47 milliseconds and were only reacting to
  • 00:11:50 change the wins so with this if I save
  • 00:11:53 this and now we have a look at our
  • 00:11:55 application I'll ever watch this city
  • 00:11:59 found and I'll use anniversary like
  • 00:12:02 Chicago do you see how it waited until
  • 00:12:06 it updated so I obviously this type so
  • 00:12:09 that's trans again Chicago and only
  • 00:12:13 updated offer was finished instead of
  • 00:12:14 all the time but if I add always here
  • 00:12:18 nothing changes but if I remove
  • 00:12:20 characters you see it changes but if I
  • 00:12:25 quickly change the back get it back
  • 00:12:27 again we got this request and we're not
  • 00:12:30 spamming the server with requests so
  • 00:12:33 this has been an important step here of
  • 00:12:36 course the next step is to add the city
  • 00:12:39 to our list now this is very simple we
  • 00:12:43 no longer need to pass the form here so
  • 00:12:46 I can get rid of this don't need that
  • 00:12:48 anymore I will also get rid of the
  • 00:12:52 observer book or I will leave the part
  • 00:12:53 in the middle because I still need to
  • 00:12:56 construct when you've ever item however
  • 00:12:58 what I do here is I can simply access
  • 00:13:01 this data because here we're already
  • 00:13:05 storing the found city in this data
  • 00:13:07 field so I can just add this this
  • 00:13:10 keyword keyword and with this we should
  • 00:13:14 be good to go and now a last time I'll
  • 00:13:17 have a look at this app load Berlin
  • 00:13:20 click add city and here we get Berlin
  • 00:13:22 and this is the state in which I wanted
  • 00:13:25 now in the next when you will have a
  • 00:13:27 look at how to set up profiles