Book Image

Angular UI Development with PrimeNG

By : Sudheer Jonna, Oleg Varaksin
Book Image

Angular UI Development with PrimeNG

By: Sudheer Jonna, Oleg Varaksin

Overview of this book

PrimeNG is a leading UI component library for Angular applications with 80+ rich UI components. PrimeNG was a huge success in the Angular world and very quickly. It is a rapidly evolving library that is aligned with the last Angular release. In comparison with competitors, PrimeNG was created with enterprise applications in mind. This book provides a head-start to help readers develop real–world, single-page applications using the popular development stack. This book consists of 10 chapters and starts with a short introduction to single-page applications. TypeScript and Angular fundamentals are important first steps for subsequent PrimeNG topics. Later we discuss how to set up and configure a PrimeNG application in different ways as a kick-start. Once the environment is ready then it is time to learn PrimeNG development, starting from theming concepts and responsive layouts. Readers will learn enhanced input, select, button components followed by the various panels, data iteration, overlays, messages and menu components. The validation of form elements will be covered too. An extra chapter demonstrates how to create map and chart components for real-world applications. Apart from built-in UI components and their features, the readers will learn how to customize components to meet their requirements. Miscellaneous use cases are discussed in a separate chapter, including: file uploading, drag and drop, blocking page pieces during AJAX calls, CRUD sample implementations, and more. This chapter goes beyond common topics, implements a custom component, and discusses a popular state management with @ngrx/store. The final chapter describes unit and end-to-end testing. To make sure Angular and PrimeNG development are flawless, we explain full-fledged testing frameworks with systematic examples. Tips for speeding up unit testing and debugging Angular applications end this book. The book is also focused on how to avoid some common pitfalls, and shows best practices with tips and tricks for efficient Angular and PrimeNG development. At the end of this book, the readers will know the ins and outs of how to use PrimeNG in Angular applications and will be ready to create real- world Angular applications using rich PrimeNG components.
Table of Contents (11 chapters)

Communication between components

Components can communicate with each other in a loosely coupled manner. There are various ways Angular's components can share data, including the following:

  • Passing data from parent to child using @Input()
  • Passing data from child to parent using @Output()
  • Using services for data sharing
  • Calling ViewChild, ViewChildren, ContentChild, and ContentChildren
  • Interacting with the child component using a local variable

We will only describe the first three ways. A component can declare input and output properties. To pass the data from a parent to a child component, the parent binds the values to the input properties of the child. The child's input property should be decorated with @Input(). Let's create TodoChildComponent:

@Component({
selector: 'todo-child',
template: `<h2>{{todo.title}}</h2>`
})
export class TodoChildComponent {
@Input() todo: Todo;
}

Now, the parent component can use todo-child in its template and bind the parent's todo object to the child's todo property. The child's property is exposed as usual in square brackets:

<todo-child [todo]="todo"></todo-child>

If a component needs to pass the data to its parent, it emits custom events via the output property. The parent can create a listener to a particular component's event. Let's see that in action. The child component ConfirmationChildComponent exposes an EventEmitter property decorated with @Output() to emit events when the user clicks on buttons:

@Component({
selector: 'confirmation-child',
template: `
<button (click)="accept(true)">Ok</button>
<button (click)="accept(false)">Cancel</button>
`
})
export class ConfirmationChildComponent {
@Output() onAccept = new EventEmitter<boolean>();

accept(accepted: boolean) {
this.onAccept.emit(accepted);
}
}

The parent subscribes an event handler to that event property and reacts to the emitted event:

@Component({
selector: 'confirmation-parent',
template: `
Accepted: {{accepted}}
<confirmation-child (onAccept)="onAccept($event)"></confirmation-child>
`
})
export class ConfirmationParentComponent {
accepted: boolean = false;

onAccept(accepted: boolean) {
this.accepted = accepted;
}
}

A bi-directional communication is possible via services. Angular leverages RxJS library (https://github.com/Reactive-Extensions/RxJS) for asynchronous and event-based communication between several parts of an application as well as between an application and remote backend. The key concepts in the asynchronous and event-based communication are Observer and Observable. They provide a generalized mechanism for push-based notification, also known as the observer design pattern. Observable represents an object that sends notifications, and Observer represents an object that receives them.

Angular implements this design pattern everywhere. For example, Angular's Http service returns an Observable object:

constructor(private http: Http) {}

getCars(): Obvervable<Car[]> {
return this.http.get("../data/cars.json")
.map(response => response.json().data as Car[]);
}

In case of the inter-component communication, an instance of the Subject class can be used. This class inherits both Observable and Observer. That means it acts as a message bus. Let's implement TodoService that allows us to emit and receive Todo objects:

@Injectable()
export class TodoService {
private subject = new Subject();

toggle(todo: Todo) {
this.subject.next(todo);
}

subscribe(onNext, onError, onComplete) {
this.subject.subscribe(onNext, onError, onComplete);
}
}

Components can use this service in the following way:

export class TodoComponent {
constructor(private todosService: TodosService) {}

toggle(todo: Todo) {
this.todosService.toggle(todo);
}
}

export class TodosComponent {
constructor(private todosService: TodosService) {
todosService.subscribe(
function(todo: Todo) { // TodoComponent sent todo object },
function(e: Error) { // error occurs },
function() { // completed }
);
}
}