Categories
Angular Javascript MEAN stack Typescript

How to use and customize Angular Material snackbars

I will write this post because, despite it is a wonderful component,  customizing Angular Material snackbars is easy but sometimes can be a little tricky.

What is a snackbar?

https://material.angular.io/components/snack-bar/overview

As they say in the documentation, snackbar is a service for displaying snack-bar notifications.

To use it you must install angular material

https://www.npmjs.com/package/@angular/material

We hope Angular Team don´t deprecate it like they have done with the popular flex-layout library. which maybe will suppose a big problem for many projects where devs will have to spend weeks or months refactoring to CSS. I hope this is not the way Angular will take in the future.

https://betterprogramming.pub/farewell-flex-layouts-is-angular-starting-to-become-a-worry-4eea953b717b

Well, once we shared that disappointing news for the Angular community, we will focus on this helpful component, which is very useful to show messages to the user on the screen, in a very easy way.

We will take as example the Superheros app I am currently creating (yep, not the most original thing, I know 😛 ).

With snackbars I can notify the user when one hero has been successfully created; or when it has been deleted; or when an error occurs.

As you see, we have created a new hero with no problems and the user has been properly informed.

And, what if an error happens? We could also inform if, for example we try to create a new hero with no name. That is not allowed so in this case snackbar will throw an error and it will be red

Of course we could disable the “save” button until required conditions to create one hero are fulfilled, but this way I can  show you the uses of snackbar for this purpose.

Well, we will show the code. If we go again to the documentation, all snackbars are white by default:

But if we go to the element´s API, we will find a property called “panelClass” which allows us to use one string or array of strings, corresponding to the names of the CSS classes that will help us to customize our snackbar.

https://material.angular.io/components/snack-bar/api

LET´S CODE

So, ok, we will start writing our snackbar.

First of all, you will have to import the Module, like explained in the documentation:

That Module will contain everything you need to use your snackbars.

Where do you have to import it? Well, it is a Module, so we could import it on the main app.module.ts of the application, but, as when we use material components we end up having a lot of modules imported, I recommend creating another module only to declare the material components we will use.

For example: create a folder and inside a file with the name material-module.ts

Notice that here we have only used the exports[] array, while many times we also import the modules with the imports[] array, for example, in the app-module.ts

We can see why here:

https://stackoverflow.com/questions/39062930/what-is-the-difference-between-declarations-providers-and-import-in-ngmodule

  • imports makes the exported declarations of other modules available in the current module
  • exports makes the components, directives, and pipes available in modules that add this module to imports. exports can also be used to re-export modules such as CommonModule and FormsModule, which is often done in shared modules.

So, what we have in our material-module, is a module that will export the Angular Material modules, so they can be used on another module with the imports[] array. We need nothing more here.

Then, those exported Material Modules will be used, in my case, in another module called heroes-module.ts, just simply by importing the MaterialModule. That way, we will have with one sentence all the exported modules available for our heroes-module.ts. dependent components. Those dependent components are inside the “declarations” array.

IMPORTANT: Depending on the Code editor you use, maybe you will have to import manually the components or modules you specify in the @NgModule, inside declarations[], imports[]… arrays. Visual Studio Code makes for you.

Well, now we are able to use our snackbar in our components. In my case for this example is the add-component.ts which I use to add new heros

Why can we use Snackbar inside this component now? Because remember: inside the heroes-module.ts, we declared the AddComponent, as well as we have imported also in heroes-module.ts our MaterialModule.

So, AppComponent “depends” on heroes-module.ts,  which can “share” with its dependent components all the modules imported on heroes-module-ts, like for example our MaterialModule

If that sounded a bit confusing, maybe this scheme helps you:

Check the gists and I will stress the aforementioned  stack overflow link where they talk about import, exports, declarations…

https://stackoverflow.com/questions/39062930/what-is-the-difference-between-declarations-providers-and-import-in-ngmodule

So, now, in the component where we need to show our snackbar, we will have to inject it in the constructor. Why? Because, as we have read at the beginning, from the doc:

MatSnackBar is a service for displaying snack-bar notifications.

And what means that it is a service? That we have to inject it (more about dependency injection here). So, in our add-component.ts:

Now in this same component,  I will create a method to show our snack bar when needed, with the customizations we wish.

EDIT: Sorry for the mistyping, in the code I wrote “succesful” instead of “successful”

As we can see, our showSnackBar() method  has 2 parameters:

  • messageToShow. As it says, the message will be shown
  • snackBarClass. In my case there will be just one string. Please notice, we have passed a default value to this parameter. It is a string with the name of the CSS class that will be used most of the times. Declaring a default value you can in this case simply call the method passing the first parameter and will show “successful” styles by default. We will see later.

Our inject service is called “snackbar”, and we will call its open() method.

Here you can find info about the method and the parameters it accepts, but basically is responsible for showing –opening- our snackbar.

https://material.angular.io/components/snack-bar/api

  • Our first parameter is the messageToShow, that will be taken from the first parameter of showSnackBar(). As you can see this method acts like a wrapper to make it easier later to call and open the snackbar.
  • Second parameter “Close!” is just the text that will be shown, you can push on it, and the snackbar disappears before the set duration ends
  • As third parameter we have an object where will use two properties:
    • Duration. Simply the ms (milliseconds) you want the snackbar to stay on screen. 1000ms=1 second.
    • panelClass. This is where we will pass our css customizations. In this case we will pass the snackBarClass which, if we remember, has the value “successful”. So in anyway, now it would be like writing:
panelClass:”successful”

So now, we only have to call our showSnackBar()  where we need, with the appropriate message to be shown, For example, when we correctly add a new Hero.

And we will have:

Have you noticed how, as we call the method, we only passed the value to the message parameter? That saves us time and work, since we passed a default value for the second parameter and then we don´t need to specify a value if it is not different from the default value (we will see that later).

But ey! Where are the css classes we need? Where is our “successful” class?

Maybe you would place it on the add-component.css , but if you do that, it won’t work, as explained here:

https://stackoverflow.com/questions/47901127/angular-5-material-snackbar-panelclass-config

Accepted answer tells us WE MUST DO IT IN OUR GLOBAL STYLES.CSS FILE

So we will go there and we will write 2 classes: our old friend “successful” and another to show different styles if there is an error

Now, if we want to show a different style when an error occurs, we will have to call the method this way:

Can you see this time we are passing also the value to the second parameter? This way, we overwrite the default value passed to the panelClass from “successful” to “fail”).

As we have already seen, this will allow us to show a proper error message with a red background:

And that’s it! Is not very difficult but having to declare the snackbar classes on the global styles.css can give you some headaches and I want to save them for you 🙂

Also we have reviewed some cool Angular concepts which maybe are useful to you.

Of course as I always say, please feel free to contact me if you find some kind of failure, or if you want to hire me as technical writer for your publication.

 

Cover image belongs to Lawrence Monk found in Pixabay

Categories
Angular Javascript Typescript Useful software

How to see object properties on Angular templates

UPDATE OCTOBER 2022: If you are using Visual Studio Code sometimes you could find you should restart IDE to be able to access object´s properties on the template.

Recently we have discussed about how to create custom Typescript interfaces with quicktype.io. In this article we will learn how to see object properties on Angular templates.

One of the advantages of creating our custom Typescript interfaces is, Typescript can infer an object´s properties this way:

GIF to illustrate how to navigate through an Object with custom Typescript interfaces and types It would be great if we could do the same in our templates, isn´t it? Fortunately, there is a way, installing Angular Language Services, a Visual Studio Code extension.

With it, you could have the same feature for your Angular templates. This way you could so something like this, which is extremely useful, as you can see:

GIF to show how to use advantages of Angular Language Service extension in our Angular templates

Just a note: to make this work, Typescript must know the specific type of the property. In our case, APIdata will contain an array of Datum type objects, so we must declare and initialize this way:

  public APIdata:Datum[];

And inside the constructor:

    this.APIdata=[];

If you do something like declaring the property with an any type, it won´t work.

See more of our Angular or Typescript related articles.

Categories
Angular HTML Javascript Projects Typescript

Easily create custom Typescript interfaces with quicktype.io

I am sure you, as a web developer, have faced a lot of times the problem of having to deal with complex Objects in your Typescript or Angular projects. One way to do it is creating our custom Typescript interfaces or classes, but it could give us a lot of work when, as said, the objects are too complex . We will see in this article how to create our Typescript interfaces using a powerful tool called Quicktype.io . This tool can be accessed through the website but also as a Visual Studio extension.

Probably many of you are experienced developers who know the benefits of Typescript interfaces and custom types much better than me, but the point here is, among everything, how to use quicktype.io to deal with big Objects, and to make an interface for those big Objects in less than a minute even if they have dozens of properties.

First of all, we will see a piece of code which shows us one typical response returned by an HTTP request in Angular, from the Giphy API. I am currently developing an app which uses Giphy API to show images, among other functionalities, and I will use some pieces of code to show you how to use it and the great advantages of creating your custom Typescript interfaces.

This time, as it is a long code, will just link it and not embed, for readability reasons:

https://gist.github.com/Franweb79/58671911ea12b583adc7712efb82d369

As you can see, it is an Object with a lot of properties, nested ones… it is easy to have errors trying to access those properties, and is very difficult to trace a path to one nested property, you could have mistyping errors…

Advantages creating custom Typescript interfaces

With Typescript interfaces, we will be able to avoid the errors mentioned above more easily, taking advantage of the help that Typescript can give us to access an Object and its properties.

Not only that: as mentioned above, with Quicktype.io we will be able to create our Typescript interface for such complex Objects fast and easily.

Let´s imagine we will request 10 items from Giphy with our HTTP request. The limit of items can be as a query parameter, as we will see later. Please read Giphy documentation to know more about it.

The result will be a very big Object with thousands of lines. But it doesn´t matter. Let´s see the code. First we will intentionally use a typical bad practice to request data, using the “any” types.

Bad way of requesting data: using “any” type

This would be our HTTP request. The ApiData property is where we will store our data to be shown in the template.

As you can see we have declared a variable called wholeQueryString where we can set the limit of items we want to request. To see more info about the other parameters I recommend you again to visit Giphy for Developers documentation.

  let wholeQueryString:string=`${URL}${Key}&limit=10&q=${searchQueryParameter}`;

Also we have set the property and the parameter for the HTTP request as “any”. Sometimes developers use this to avoid Typescript throwing errors. For example, when we do

 this.APIdata=response.data;

If we don´t declare the response as “any”, Typescript will say something like “ey, this is a generic Object type, I can´t see a data property inside because it is not part of a generic Object type”.

image to show typescript error when not using proper typescript interfaces, but the any type

We can solve it by setting the response as “any”, it is like telling Typescript: “Is OK, I know what I am doing, just let me do”. Then it won´t complain:

image to illustrate a bad way to fix error with the any type

But this way, we must know our response Object structure; we must check the properties and know our response has a data property. That can get worse if we must access something like

response.data[0].url

As mentioned above, it is easy that you have errors trying to follow complex, nested property paths.

It is a solution, our software will work; but is not the best way to do it.

Using quicktype.io to create our Typescript interfaces

Let´s create then our custom Typescript interface, see how it helps us, and how to create it with quicktype.io

If you know something about Typescript interfaces, you can figure out how hard it would be to build our interface for an Object as we get on this Giphy response, isn´t it? Imagine you have to check more than 20 properties, declare types… and same for nested Objects.

Fortunately we will use quicktype.io to do that now.

First we run our HTTP code.

As we have a

console.log (response);

It will show us the complete Object that Giphy returns.

image to illustrate an object returned by angular HTTP request

We just copy the entire Object and paste it inside the left panel of quicktype.io. It will transform our JSON Object into typesafe code in any language, including Typescript.

Remember to copy the entire Object, just right-click over it and select “copy object”, works the same for Firefox and Google Chrome.

You must write a name for your Typescript interfaces, in this case we will use GiphyResponse. Then, in the options button you can select the language you want the JSON to be parsed. In our case it is Typescript.

image to show how to parse a JSON into custom Typescript interfaces

And that’s it! We have a complete interface of our long response in less than one minute!

Using the quicktype.io generated data for our projects

Now that we have the code, we just can copy and paste it to create our own Typescript interfaces inside our Angular project.

First we will create a file called

giphy-response-interfaces.ts

Preferably do it inside an “interfaces” folder. Just copy the code generated by quicktype.io

Now we are ready to use our custom Typescript interfaces wherever we need inside our project. And now, we will use it to handle Objects easily with the help that Typescript can give us.

We will change the “any” types we have written before, with our new custom type, GiphyResponse, or derived ones.

We can see our interface has now image to show structure generated for our custom Typescript interfaces The relevant data we need, as its own name says, will be inside the “data” property.

Remember we will store our data inside a property. As we see, the data is an array of Datum type, so we change:

 public APIdata:any;

to

 public APIdata:Datum[];

As it is an array, we can initialize inside the constructor it simply as:

   this.APIdata=[];

Now we must change the HTTP response code. So you can replace this:

for this:

Apart from the type change we have done for the property, we can see we changed two things inside the HTTP request:

 this._http.get<GiphyResponse>
  • Now the response parameter has also our custom type. Please note that it would now work even just leaving the response without type:
next: (response)=>{

        this.APIdata=response.data;

       

        console.log (response);

      }

But I humbly think it is a better idea to specify this response with our custom type

next: (response:GiphyResponse)=>{

        this.APIdata=response.data;

       

        console.log (response);

      }

Well, and where is the advantage of all of this?

Look what happens now:

gif image to describe advantages of using custom Typescript interfaces

Yes! Now Typescript knows the structure and property of the Object, thanks to our custom Typescript interfaces. We have told Typescript something more specific and well described than a vague “any” type so it can help us.

The best advantage is that, if we have to access now to any nested property inside the object, we can do it much more easily, with Typescript safely guiding us through the structure of the Object.

Look at this. Remember data property is an array, so we could do, for example, for first element of the array:

second GIF to illustrate how to navigate through an Object with custom Typescript interfaces and types

You can see all nested properties, objects… much easier than exploring the browser console and following the paths by yourself, right?

I hope this article was useful for you. Remember to check other Angular or Typescript related articles we have written.

 

Image by James Osborne found in Pixabay