Angular with Bulma CSS Framework | Modal Component, @Input and @Output decorators

Edigleysson Silva

--

The best way to learn it is by practicing. Which is true, but the more interesting a practice, the easier and fun it is to learn. Well, that’s why I bring another tutorial on Angular with Bulma.

Let’s do a mix and learn several things at once. Come with me!

In this tutorial, we will understand a bit about the operation of the @Input and @Output decorators. For this we will use the modal component of the Bulma CSS framework. The idea is to do an action between two components, in which one will pass properties to the other.

Basically we will have a parent component that calls a mode to select an object and after selection the selected item will be displayed in the parent component.

Before we can use our modals we will need to know some concepts about Angular. These are @Input, @Ouput and EventEmitter. So let’s go

By the way, in order to follow this tutorial you need to understand how to add Bulma CSS to your app. The good news is that I have a tutorial that will help you with this

Now that you know how to add Bulma we can continue.

Step 1: Some concepts

From Angular Doc:

  • @Input: Decorator that marks a class field as an input property and supplies configuration metadata. The input property is bound to a DOM property in the template. During change detection, Angular automatically updates the data property with the DOM property’s value.
  • @Output: Decorator that marks a class field as an output property and supplies configuration metadata. The DOM property bound to the output property is automatically updated during change detection.
  • EventEmitter : Use in directives and components to emit custom events synchronously or asynchronously, and register handlers for those events by subscribing to an instance.

In a less formal definition and better placed here for our example. The @Input decorator is for passing information to a child component and @Output decorator is used to return a value for the parent component. About EventEmitter, this is the definition that I think most appropriate, basically it emit events hehe.

EventEmitter and @Output will be used together to return data to the parent component.

Step 2: Setup

Create the command with the command

ng new bulma-angular-modal

After executing this command, create a component with the command

ng g c modal

Our components are created. They are app and modal, see the structure of the files in the VS Code below:

Image 1 — VS Code File Structure

As you may have guessed, app will be our parent component and modal will be our child component. To complete this step, add the modal component to the app component.

To do this, simply put the modal component selector in the app.component.html file. See:

Image 2 — app.component.html with modal component selector

The class in heading element is only to show large text. Run the application with the command ng serve see the result in the browser. You will see the page looks like the image:

Image 3 — App running

Awesome! Our app is running. Let’s go to understand modal in the next step.

Step 3: Modal component

To use a modal in Bulma CSS we need to create a structrure with the following elements:

  • .modal — main container, that contains all element of a modal
  • .modal-background — the layer behind the modal
  • .modal-content — the element that contains the modal content
  • .modal-close — the icon close

See below a simple modal with a paragraph with the famous “Lorem ipsum…”. This paragraph is inside of a <div class="box"> .

Image 4 — Simple modal example

Access http://bulma.io to see more example about modals.

So, in this tutorial we will use another style of modal that is Card Modal. That style is a classic modal with head, body and foot. Our modal content should have a select element with some items. The code is below. Copy the code and paste in the modal.component.html file.

Code 1 — Modal code

If you run your application, you’ll see …. nothing! This is so frustrating! Something is wrong with or app? Keep calm, our app is ok.

We have forgotten a little detail in our modal, .is-active class. This class is responsible for toggling the visibility of our modal. You remember that Bulma does not use CSS, right?

To fix it, you should add the class .is-active to the .modal element. Something like:

<div class="modal is-active">
....
</div>

After that you will see this working perfectly. Lik this:

Image 5 — Modal working

Our modal is working, that’s great!

Step 4: Programmatically toggle

Our modal is awesome, but we have no dinamicity let’s to solve it.

First of all we need to create a flag in the app.component.ts file. This flag is a boolean property that will be responsible to control the visibility of modal component, like:

showModal: boolean = false;

After we will add a verification in the app.component.html file to handle the visbility. We will use the *ngIf directive, like:

<app-modal *ngIf="showModal"></app-modal>

Then, add a button and when this button is clicked, the flag will be true. See the snippet of app.component.ts below:

....export class AppComponent {
showModal: boolean = false;
selectItem() {
this.showModal = true;
}

}

Now see the app.component.html file with the button and click event:

<h1 class="is-size-2">@Input and @Output Demo</h1><button class="button is-primary" (click)="selectItem()">Choose</button><app-modal *ngIf="showModal"></app-modal>

Note the button with click event.

Now when you run your app and click in the button you can see that the modal is visible.

But wait. How can I close the modal? Keep calm, let’s fix it right now!

Now we will use the modal.component.ts file and we will use the @Output decorator and EventEmitter from “@angular/core” package.

We need to add a property to issue events. These events will be emitted when the modal is closed, for example, when the user clicks the cancel button.

So, this property is a EventEmitter object and is assigned with a @Output decorator.

Add a method to emit events too. This method will use the property to emit events e pass informations to the parent component.

See the snippet below:

...export class ModalComponent implements OnInit {   @Output()
onClose = new EventEmitter();
constructor() { } ngOnInit() {
}
cancel() { this.onClose.emit(null); }
}

Now, in the modal.component.html file we need to attach the click add in the cancel button and close buttonelement. See:

<div class="modal is-active">
...
<button class="delete" aria-label="close" (click)="cancel()></button>
...
<footer class="modal-card-foot">
<button class="button is-success">Save changes</button>
<button class="button" (click)="cancel()">Cancel</button>
</footer>
</div>
</div>

Finally, in the app.component.hml file we will get the event and close the modal. Our file is something like this:

<h1 class="is-size-2">@Input and @Output Demo</h1><button class="button is-primary" (click)="selectItem()">Choose</button><app-modal *ngIf="showModal" (onClose)="showModal=false"></app-modal>

Note the (onClose) in the app-modal elemento. That’s exactly the property onClose of modal. If you run your app will see that the toggle is working perfectly.

What happens here is that when the cancel button is clicked, an event is issued. This event is retrieved by the Output property that is in the modal.

Step 5: Passing data between components

You may have noticed that our modal has a select field.

<select name="selected" [(ngModel)]="selected">
<option value="">Select a item</option>
<option value="Item 1">Item 1</option>
<option value="Item 2">Item 2</option>
</select>

In this field you can see the ngModel property. Let’s use them to handle the selection.

First of all, we need to create a property in the modal.component.ts file. These property is selected that will be assigned with the @Input. That mean that the parent component can set these property.

...export class ModalComponent implements OnInit {

@Input()
selected: string = '';
@Output()
onClose = new EventEmitter();
constructor() { }
...

Now add a method to handle the click in save button. Like:

...cancel() {this.onClose.emit(null);}
selectedItem() { this.onClose.emit(this.selected) }
...

Note that we are emitting a event again. But in this time the event send the selected item. Our modal is ready to send the selected item. Let’s to the app component to get it.

In the app.component.ts file, add a property selected typed as a string (without decorator). Then, make a method to hide modal and get the selected item. See the code:

Now see the HTML code for app component:

Some changes here.

First, we added a paragraph to show the selected item. Then we change the (onClose) content addig the selectedItem() method. Note that in the method we passa a $event. But what is $event? Where did that come from?

So, rememember emit in the modal.component.ts? So, the param in the emit() methos is the $event. Thus, when the user clicks the SAVE button, the selected item is passed to the application component and when the user cancels the null value is passed.

But wait, where is the @Input usage?

Oh, I almost forgot. Sorry about that.

When modal open, the selection field is set to “Select an item”. To improve this, we can send the selected value and when modal open, the selection input will be set with the previously selected value.

Our modal already have a @Input decorator and we need only to change the app.component.html file. See the changed snippet:

<h1 class="is-size-2">@Input and @Output Demo</h1>...<app-modal [selected]="selected" *ngIf="showModal" (onClose)="selectedItem($event)"></app-modal>

Thus, the parent component passes to the child component a value. In our case the modal will already have the selected value defined with that passed by the app.

It’s over! Run your app and see the magic!

Conclusion

This was a small example to show you how you can pass data between components. There are some validations that could be made in our item selection application and you can do them.

That is all! See ya!

See more about

  • Bulma CSS Framework (https://bulma.io)
  • Angular (https://angular.io)

--

--

Responses (1)