Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

AngularJS Hosting Europe - HostForLIFE :: What is the difference between ng-container, ng-template, and ng-content?

clock August 2, 2023 10:51 by author Peter

In this article, learn about ng-container, ng-template, and ng-content in angular


In the context of Angular, ng-container, ng-template, and ng-content are three different Angular directives that serve different purposes. Let's explore each one:

ng-container

The ng-container directive is a non-rendered element that is used to group and manage structural directives, such as *ngIf, *ngFor, etc. It acts as a placeholder or wrapper for these structural directives when they need to be applied to multiple elements or when you want to use them without adding an additional DOM element. The ng-container itself doesn't create any extra elements in the final DOM, making it a useful tool for organizing and applying structural directives without affecting the layout.
<ng-container *ngIf="condition">
  <!-- Elements to show when the condition is true -->
</ng-container>

ng-template
The ng-template directive defines an Angular template that can be used to encapsulate HTML markup and Angular code that won't be rendered immediately. It acts as a template placeholder and can be referenced using the *ngTemplateOutlet directive or by using the <ng-container> element with the *ngTemplateOutlet attribute. ng-template is particularly useful when you want to reuse a piece of HTML code with its associated logic in multiple places.
<ng-template #myTemplate>
  <!-- Template content here -->
</ng-template>

<ng-container *ngTemplateOutlet="myTemplate"></ng-container>


ng-content
The ng-content directive is used to create content projection slots within a component. It allows you to pass content from the parent component to the child component's template. When you define <ng-content></ng-content> in the child component's template, it acts as a placeholder for the content that will be projected into it from the parent component.

Example. Parent Component Template.
<app-child>
  <!-- Content to project into the app-child component -->
</app-child>

As per the above snippet, the content is within the <app-child> tag.

Happy learning :)



Node.js Hosting Europe - HostForLIFE.eu :: Image Generation Using OpenAI API and Node.js

clock July 6, 2023 09:26 by author Peter

DALL-E, developed by OpenAI, is an AI model that can generate images from textual descriptions. It combines the power of deep learning and generative modeling to create unique and imaginative visual outputs based on the provided text prompts. This technology has sparked excitement among researchers, artists, and developers alike.


To make the capabilities of DALL-E accessible to developers, OpenAI has released the DALL-E API. This API allows developers to interact with the DALL-E model programmatically; by using this, developers can generate images by giving text prompts. By using Node.js and  DALL-E, we can generate images programmatically.

Note. If you want to achieve this using Python, Please read my previous article on how to Generate Image Using DALL-E API and Python.

Prerequisites
It is essential to have a basic understanding of the following concepts and technologies.

Node.js
Node.js is a JavaScript runtime environment that allows you to run JavaScript code outside of a web browser. To use Node.js, you'll need to install it on your machine. Install Node.js from the official website.

Basic API Concepts

A basic understanding of API (Application Programming Interface) concepts is crucial. APIs provide a way for different software applications to communicate and exchange data. Familiarize yourself with concepts like endpoints, HTTP methods (GET, POST, etc.), request/response structure, and how to handle API responses using JavaScript.

Setting Up the Project

Open your terminal or command prompt and follow these steps.
    Create a new directory for your Project.
    mkdir dalle-image
    cd dalle-image


Initialize a new Node.js project by running the following command.
npm init -y

This will create a package.json file, keeping track of your Project's dependencies.

Install Required Dependencies
Install the Axios library to make API requests to the DALL-E API. Axios is a popular JavaScript library for making HTTP requests. It simplifies the process of sending asynchronous requests and handling responses. To install it, use the following command
npm install axios

Now, Axios is added to your Project's dependencies, and you can start using it to interact with the DALL-E API.

Writing the Node.js Code

Write the code to interact with the DALL-E API using Node.js. Follow the steps below.

Setting up the API Endpoint and Authorization

Navigate to the dalle-image directory and create a new JavaScript file, for example, dalle-api.js.
Require the Axios module at the top.
const axios = require('axios');

Next, declare a constant variable to store your DALL-E API key.
const API_KEY = 'YOUR_API_KEY';

Implementing the API Call using Axios
Implement the API call using Axios.
const axios = require('axios');
const API_KEY = 'YOUR_API_KEY';   //replace with your key

const generateImages = async () => {
  try {
    const response = await axios.post(
      'https://api.openai.com/v1/images/generations',
      {
        prompt: 'A beautiful sunset over a serene lake',
        n: 1,                                //define the number of images
        size: '512x512',                     //define the resolution of image
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${API_KEY}`,
        },
      }
    );

    console.log(response.data);
    // Handle the response here, e.g., extract image data and display or save it.
  } catch (error) {
    console.error('Error:', error.response.data);
  }
};

generateImages();


In the code above, we use the Axios. post method to make a POST request to the API endpoint. We pass the request payload as the second argument to the method and include the API key in the request headers.

Now run the Project using the following command.
node dalle-api.js

Check the console output to see the API response or any errors that occurred during the process.

Output



AngularJS Hosting Europe - HostForLIFE :: Advanced RxJS Patterns in Angular

clock July 3, 2023 08:45 by author Peter

Reactive Extensions for JavaScript (RxJS) have become the backbone of modern Angular applications, enabling developers to handle complex asynchronous operations with elegance and ease. While many developers are familiar with basic RxJS operators, there are advanced patterns that can take your Angular development skills to the next level. In this article, we will explore some lesser-known yet powerful RxJS patterns that can significantly improve your developer experience.


1. Canceling Previous Requests with SwitchMap
One common scenario is handling user input, such as search queries, that trigger API calls. To prevent outdated responses and save bandwidth, we can use the switchMap operator. It automatically cancels previous requests when a new request is made.

Let's take a look at an example.
import { fromEvent } from 'rxjs';
import { switchMap } from 'rxjs/operators';

// Get the search input element
const searchInput = document.getElementById('search-input');

// Create an observable from input events
const searchObservable = fromEvent(searchInput, 'input').pipe(
  map((event: any) => event.target.value),
  switchMap(searchTerm => makeApiCall(searchTerm))
);

searchObservable.subscribe(response => {
  // Handle the API response
});


2. Throttling API Calls with DebounceTime
In scenarios where user input or events trigger API calls, we might want to throttle the rate of API requests to avoid overloading the server. The debounceTime operator can help us achieve this by delaying the emission of values from an Observable. Let's see it in action.
import { fromEvent } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

// Get the search input element
const searchInput = document.getElementById('search-input');

// Create an observable from input events
const searchObservable = fromEvent(searchInput, 'input').pipe(
  map((event: any) => event.target.value),
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(searchTerm => makeApiCall(searchTerm))
);

searchObservable.subscribe(response => {
  // Handle the API response
});

3. Sharing Cached Results with ShareReplay
Sometimes, we want multiple subscribers to receive the same cached result from an Observable. The shareReplay operator enables us to achieve this by caching and sharing emitted values. This is useful in scenarios where we want to avoid redundant API calls. Let's take a look.
import { interval } from 'rxjs';
import { take, shareReplay } from 'rxjs/operators';

// Create an interval observable that emits values every second
const sourceObservable = interval(1000).pipe(
  take(5),
  shareReplay(1) // Cache and share the emitted values
);

// Subscriber 1
sourceObservable.subscribe(value => {
  console.log(`Subscriber 1: ${value}`);
});

// Subscriber 2
setTimeout(() => {
  sourceObservable.subscribe(value => {
    console.log(`Subscriber 2: ${value}`);
  });
}, 3000);

4. Sequential Requests with ExhaustMap
In certain scenarios, we may need to perform a series of actions that depend on the completion of previous actions. The exhaustMap operator allows us to achieve this by ignoring new source values until the current inner Observable completes. Let's see it in action.
import { fromEvent } from 'rxjs';
import { exhaustMap } from 'rxjs/operators';

// Get the button element
const button = document.getElementById('button');

// Create an observable from button click events
const clickObservable = fromEvent(button, 'click').pipe(
  exhaustMap(() => performAction())
 );

clickObservable.subscribe(() => {
// Handle the action completion
});

5. Error Handling and Retries with RetryWhen
Handling errors and implementing retry logic is essential for robust applications. The `retryWhen` operator allows us to handle errors and retry the Observable based on specific conditions. Let's take a look.
import { throwError, timer } from 'rxjs';
import { mergeMap, retryWhen, delayWhen } from 'rxjs/operators';

// Create an observable that throws an error
const errorObservable = throwError('Something went wrong!');

// Retry the observable after a delay
errorObservable.pipe(
  retryWhen(errors =>
    errors.pipe(
      mergeMap((error, index) => {
        if (index === 2) {
          return throwError('Max retries reached'); // Throw error after 3 attempts
        }
        return timer(2000); // Retry after a 2-second delay
      })
    )
  )
).subscribe({
  next: () => console.log('Success!'),
  error: (error) => console.log(`Error: ${error}`)
});


By harnessing the power of advanced RxJS patterns in Angular, we can greatly enhance our developer experience. The switchMap, debounceTime, shareReplay, exhaustMap, retryWhen, and other operators provide us with powerful tools to handle complex asynchronous scenarios, improve performance, and build robust applications.




AngularJS Hosting Europe - HostForLIFE :: Communication Between Components In Angular

clock June 26, 2023 08:27 by author Peter

Information exchange between various application components is essential, and Angular is not an exception. Angular provides a number of built-in methods to facilitate this prevalent practise. Nonetheless, there may be instances in which these default approaches are insufficient, necessitating the implementation of more creative solutions.


In this session, we will investigate a few of the most common methods for component communication.

The resources I used to create this tutorial are listed below.

  1. Visual Studio Code
  2. Node 18.14.0
  3. Angular 15
Input and Output Properties (Parent-Child Communication)'s source code can be downloaded from GitHub.

  • You can transfer data between parent and offspring components using input properties.
  • Define an input property in the secondary component using @Input(), and then bind the property in the parent component.
  • Employ output properties with events to communicate from the child component to the parent component.
  • Define an output property in the child component using @Output() and emit events with EventEmitter.

Let's examine the sample code below, which will give you an overview of parent-to-child and child-to-parent communications.

Parent Component

  • Input and Output Properties (Parent-Child Communication)
  • You can use input properties to pass data from parent to child components.
  • Define an input property in the child component using the @Input() decorator, and then bind the property in the parent component.
  • Use output properties with events to communicate from the child component back to the parent component.
  • Define an output property in the child component using the @Output() decorator and emit events using EventEmitter.


Let us look at the sample code below, which will give you an overview of parent-to-child and child-to-parent communications.

Parent Component
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <input [(ngModel)]="parentMessage"/>
    <p>{{ childMessage }}</p>
    <app-child [message]="parentMessage" (notify)="onNotify($event)"></app-child>`

})
export class IOParentComponent {
  parentMessage = 'Message from parent';
  childMessage ="";
  onNotify(message: string) {
    this.childMessage =message;
  }
}


Child Component
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
    <h2>Child Component</h2>
    <p>{{ message }}</p>
    <input [(ngModel)]="childMessage"/>
    <button (click)="notifyParent()">Notify Parent</button>
  `
})
export class IOChildComponent {
  @Input() message: string ='';
  @Output() notify = new EventEmitter<string>();
  childMessage: string ='Message from child';
  notifyParent() {

    this.notify.emit(this.childMessage);
  }
}

Services (Cross-Component Communication) using RxJS Observables and Subjects

  • Create a service that can be injected into the components needing to communicate.
  • The service acts as a shared source of data and functionality.
  • Components can subscribe to data streams or invoke methods provided by the service to communicate with each other.


Let us take a look at the example

Shared Service
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class DataService {
  private dataSubject = new Subject<string>();

  setData(data: string) {
    this.dataSubject.next(data);
  }

  getData() {
    return this.dataSubject.asObservable();
  }
}

Component 1
import { Component } from '@angular/core';
import { DataService } from './dataservice.service';

@Component({
  selector: 'app-scomponent1',
  template: `    <h1>Component 1</h1>
    <input type="text" [(ngModel)]="message">
    <button (click)="sendMessage()">Send Message</button>
    <app-component2>/</app-component2>`

})
export class SComponentOne {
  message: string="";

  constructor(private dataService: DataService) { }

  sendMessage() {
    this.dataService.setData(this.message);
  }
}


Component 2
import { Component } from '@angular/core';
import { DataService } from './dataservice.service';

@Component({
  selector: 'app-component2',
  template: `
    <h1>Component 2</h1>
    <p>{{ receivedMessage }}</p>
  `
})
export class SComponentTwo {
  receivedMessage: string ='';

  constructor(private dataService: DataService) { }

  ngOnInit() {
    this.dataService.getData().subscribe(message => {
      this.receivedMessage = message;
    });
  }
}


The below reference link explains the Mediator and Service Bus approaches for component communication in Angular.

Component communication in Angular for Senior devs by 'iamprovidence'

These are some of the commonly used methods for component communication in Angular. The choice of method depends on the specific requirements of your application and the relationship between the components involved.



AngularJS Hosting Europe - HostForLIFE :: Mastering Angular's ngPlural Directive: Handling Pluralization with Ease

clock June 19, 2023 07:45 by author Peter

When it comes to building dynamic Angular applications, handling pluralization is a common requirement. Angular provides a powerful directive called ngPlural that simplifies the process of displaying content based on numeric values. This article will explore the ngPlural directive and learn how to leverage its capabilities effectively.

What is ngPlural?
The ngPlural directive allows us to present different content based on numeric values in our Angular templates. It provides a concise and elegant way to handle pluralization scenarios. By utilizing ngPlural, we can eliminate the need for conditional logic and achieve more maintainable code.

Implementation of ngPlural

To start using ngPlural, we need to import the CommonModule in our Angular module. This ensures that the necessary directives and components are available in our application. Once imported, we can use ngPlural in our templates.
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule
  ],
  // ...
})
export class AppModule { }


The ngPlural directive works in conjunction with ngPluralCase. Inside the ngPlural element, we define multiple ngPluralCase elements that correspond to specific numeric values or conditions. Angular evaluates the ngPluralCase blocks and renders the appropriate content based on the value provided to ngPlural.

In our template, we can define different cases using the ngPluralCase directive. We specify the value or condition for each case, allowing Angular to determine which content to display. We can have special cases for values like "=0" or "=1", and a generic "other" case that covers all other values.
<div [ngPlural]="numItems">
  <ng-template ngPluralCase="=0">No items</ng-template>
  <ng-template ngPluralCase="=1">One item</ng-template>
  <ng-template ngPluralCase="other">{{ numItems }} items</ng-template>
</div>


Best Practices and Tips

  • Be mindful of the data type: Ensure that the variable bound to ngPlural is of a numeric type, as ngPlural evaluates values based on strict equality.
  • Consider internationalization: If your application requires localization, use Angular's internationalization (i18n) features in combination with ngPlural to handle pluralization rules specific to different languages.
  • Handle complex conditions: ngPlural supports more advanced conditions by allowing you to use expressions within ngPluralCase blocks. This flexibility enables you to handle custom pluralization scenarios efficiently.


A ngPlural directive is a powerful tool for handling pluralization in Angular applications. By using ngPlural and ngPluralCase, we can easily display content based on numeric values, providing a seamless user experience. With the knowledge gained from this article, you're well-equipped to implement ngPlural and enhance your Angular applications with dynamic pluralization capabilities.



AngularJS Hosting Europe - HostForLIFE :: A New Way to Manage State in Angular Applications

clock June 14, 2023 10:42 by author Peter

Angular v16 introduces a new way to manage state in Angular applications called Signals. Signals are a more lightweight and flexible alternative to Angular's built-in Change Detection mechanism. Signals can be used to track changes to data in your application and trigger the re-rendering of components only when necessary. This can lead to significant performance improvements in large applications.


How to Use Angular Signals?
To use Signals, you first need to import the Signal class from the @angular/core library. Once you have imported the Signal class, you can create a new signal by calling the new Signal() constructor. The new Signal() constructor takes one argument, which is the initial value of the signal.

Once you have created a new signal, you can subscribe to it by calling the subscribe() method. The subscribe() the method takes a callback function as its argument. The callback function will be called whenever the value of the signal changes.

You can also use signals to create computed values. Computed values are derived values that are updated whenever the values of their dependencies change. To create a computed value that depends on a signal, you use the | async pipe.

Example
The following example shows how to use Signals to track changes to a user's name and age.
import { Component, OnInit } from '@angular/core';
import { Signal } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  name = new Signal('');
  age = new Signal(0);

  constructor() {}

  ngOnInit() {
    this.name.subscribe(() => {
      console.log('Name changed to', this.name.value);
    });

    this.age.subscribe(() => {
      console.log('Age changed to', this.age.value);
    });
  }

}

The app.component.html file contains the following code.
<h1>Angular Signals Demo</h1>
<input [(ngModel)]="name" placeholder="Enter your name">
<h2>Age</h2>
<input [(ngModel)]="age" placeholder="Enter your age">


When the user changes the value of the name or age input, the corresponding signal will be updated. The callback function that is subscribed to the signal will then be called. In this case, the callback function will log the new value of the signal to the console.

Angular Signals is a powerful new tool for managing state in Angular applications. Signals can be used to track changes to data in your application and trigger the re-rendering of components only when necessary. This can lead to significant performance improvements in large applications.



AngularJS Hosting Europe - HostForLIFE :: ng-init in Angular 15

clock June 6, 2023 10:29 by author Peter

We have mostly faced this issue while migrating from AngularJS to a higher version; since the angular higher version does not support ng-init we can use the directive to achieve that,


Init Directive(ng-init.directive.js)
We can generate a directive using the following comment ng g d [directivename], which can declare the selector name which we are going to use in the element as an attribute.

And we going set the output() emitter for the directive, which is going to init for us.
@Directive({
  selector: '[ngInit]'
})
export class NgInitDirective implements OnInit {
  @Output()
    ngInit: EventEmitter<any> = new EventEmitter();

    ngOnInit() {
        this.ngInit.emit();
    }
  }


App.Module.ts for a particular module
Register the custom pipe in the module where you want to use it. For example, open the app.module.ts file and import and add NgInitDirective to the import array:
@NgModule({
  declarations: [....,....],
  imports: [
    NgInitDirective
  ],
  providers: [ ....]

App.Component.html

    In your component's template, pass the desired value, which needs to be initialized as parameters to the (ngInit):

By assigning the value which needs to initialize before rendering the particular <div> or <span>.
<div (ngInit)="AlreadyShown=false">
<div *ngFor="let row of data">
 ....
....
</div>
</div>



European Entity Framework Hosting - HostForLIFE :: Filtering Data with Entity Framework Global Query Filters Step 1. Define Model

clock May 26, 2023 07:41 by author Peter

Step 1. Define Model
Create your entity models as usual to begin. These models should represent your entities and contain all of the necessary properties. Suppose, for instance, we have a "Product" entity:
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsDeleted {get; set; }
}

Configure the Global Query Filter
Implement an override for the OnModelCreating method in your DbContext class. Using the Entity and HasQueryFilter methods, you can configure global query filters within this method. Here's an example of excluding soft-deleted products using a global query filter:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().HasQueryFilter(p => !p.IsDeleted);
}

3. Execute Filtered Queries
Once the global query filter is configured, it will be automatically applied to any query involving the Product entity. For instance, soft-deleted products will be excluded by default when retrieving products.
activeProducts is equal to dbContext.Products.ToList();

Advantages of Global Query Filters in C#
    Data Integrity: Ensure that all queries involving the entity adhere to the desired filtering conditions, thereby fostering the consistency and integrity of the data.
    By using global query filters, you can centralize the filtering logic, making your code simpler and easier to maintain.
    Global query filters enable the exclusion of superfluous data at the database level, resulting in improved query performance and resource utilization.

Implementing global query filters in Entity Framework provides a potent tool for consistently applying filtering conditions to your entities. By configuring global query filters during the OnModelCreating method, you can ensure that the filters are applied automatically to all queries involving the specified entity, resulting in clearer code and enhanced data integrity. Test it out!



AngularJS Hosting Europe - HostForLIFE :: Improving Performance through Angular Change Detection Techniques

clock May 19, 2023 08:27 by author Peter

Change detection is an integral component of Angular that ensures the user interface is in alignment with the state of the application. ChangeDetectionStrategy is Angular's default detection strategy.Standard, which examines for modifications to all components and their templates on each JavaScript event or timer tick.


Nevertheless, this default strategy may result in superfluous and expensive change detection cycles, particularly in large-scale applications. Alternative strategies, such as OnPush, enter into play at this point. The OnPush strategy optimizes change detection by focusing solely on a component's inputs and references.

Using the OnPush strategy, Angular determines if a component's input properties have changed. If the input values remain the same, Angular assumes that the component's state hasn't changed and skips its change detection entirely. This optimization can significantly improve the performance of your Angular application, especially when used strategically.

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-user',
  template: `
    <h2>{{ user.name }}</h2>
    <p>{{ user.email }}</p>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent {
  @Input() user: User;
}

In this example, the UserComponent has the OnPush change detection strategy defined. By doing so, we instruct Angular to only perform change detection if the user input property changes.

When using the OnPush strategy, it is essential to ensure that the user input property is immutable. If you update the user object's properties, Angular won't detect the changes, as it relies on reference comparison.

To optimize performance further, you can utilize the ChangeDetectorRef to manually trigger change detection when necessary:

import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'app-user',
  template: `
    <h2>{{ user.name }}</h2>
    <p>{{ user.email }}</p>
    <button (click)="updateUser()">Update</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent {
  @Input() user: User;

  constructor(private cdr: ChangeDetectorRef) {}

  updateUser() {
    // Update the user object
    this.cdr.markForCheck(); // Trigger change detection
  }
}


In the above example, we inject the ChangeDetectorRef and call its markForCheck() method to manually trigger change detection when the user clicks the "Update" button.

By understanding and utilizing Angular's change detection strategies, especially the OnPush strategy, you can significantly enhance the performance of your Angular applications. By minimizing unnecessary change detection cycles, your app will run more efficiently and provide a smoother user experience.

Remember to carefully analyze your application's requirements and components' state before choosing a change detection strategy. Applying the OnPush strategy to components that rarely change or have immutable input properties can lead to noticeable performance improvements.



AngularJS Hosting Europe - HostForLIFE :: An Introduction to Angular and Storybook

clock May 15, 2023 10:00 by author Peter

In modern web development, creating reusable and visually appealing UI components is essential. Angular, a popular JavaScript framework, provides a robust framework for building scalable web applications. Storybook, however, is a powerful tool for developing and showcasing UI components in isolation. This article will explore the combination of Angular and Storybook to create beautiful and reusable component libraries.

Getting Started
First, let's create a new Angular project and set up Storybook within it. Open your terminal and follow the steps below.

Step 1. Create a new Angular project using the Angular CLI.
ng new my-component-library

Step 2. Change into the project directory.
cd my-component-library

Step 3. Install Storybook using the following command.
npx storybook@latest init

This will set up Storybook within your Angular project.

Step 4. Start Storybook.
npm run storybook

If everything is set up correctly, you should see the Storybook interface running at http://localhost:6006.

How to create your first Angular Component?
Now that we have our Angular project with Storybook let's create our first Angular component and showcase it in Storybook.

Step 1. Generate a new Angular component using the Angular CLI.
ng generate component button

Step 2. Open the newly created button.component.ts file in your favorite code editor and modify it as follows,
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-button',
  template: `
    <button [ngClass]="buttonClass">{{ label }}</button>
  `,
  styleUrls: ['./button.component.css']
})
export class ButtonComponent {
  @Input() label: string;
  @Input() buttonClass: string;
}

In this code, we have defined an Angular component called ButtonComponent. It accepts two inputs: label For the button text and buttonClass For applying custom CSS classes to the button element. The component's template consists of a simple button element that utilizes Angular's data binding and class binding.

Step 3. Open the button.component.css file and add some basic styling to the button.
button {
  padding: 8px 16px;
  font-size: 14px;
  border-radius: 4px;
}


Step 4. Open the button.stories.ts file in the src/app directory and modify it.

import { Meta, Story } from '@storybook/angular';
import { ButtonComponent } from './button.component';

export default {
  title: 'Components/Button',
  component: ButtonComponent,
} as Meta;

const Template: Story<ButtonComponent> = (args: ButtonComponent) => ({
  props: args,
});

export const Primary = Template.bind({});
Primary.args = {
  label: 'Primary Button',
  buttonClass: 'primary',
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: 'Secondary Button',
  buttonClass: 'secondary',
};

JavaScript

In this code, we import the necessary dependencies from @storybook/angular and import our ButtonComponent. We define a Meta as an object that includes the title of our component and the component itself.

Next, we define a Template function that takes args as input and returns an object with props set to args. This function acts as a template for rendering our component in Storybook.

Finally, we create two stories: Primary and Secondary. Each story represents a different variation of our ButtonComponent. We provide the necessary arguments (label and buttonClass) for each story and bind them to the respective inputs of ButtonComponent.

Step 5. Open your browser and navigate to http://localhost:6006 (or the URL specified in your terminal) to view the Storybook interface. You should see the Button component listed under the Components category, with the Primary and Secondary variations available for selection.

Step 6. Click on the Primary or Secondary story to see the rendered ButtonComponent in the Storybook. You can interact with the component, view its properties, and observe how it looks in different states.

Congratulations! You have successfully created your first Angular component and showcased it in Storybook.
Conclusion

Angular and Storybook complement each other perfectly when building reusable and visually appealing component libraries. Angular provides a robust framework for creating components, while Storybook allows you to develop and showcase those components in isolation, making it easier to iterate and test different variations.

In this article, we covered the basic setup of Angular and Storybook and walked through creating a simple ButtonComponent and showcasing it in Storybook. This is just the tip of the iceberg, and there's much more you can do with Angular and Storybook to build comprehensive component libraries.

Remember to experiment, explore the various features and capabilities of Angular and Storybook, and leverage the power of both tools to create stunning UI components for your projects. Happy coding!



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in