0

Suppose we have a couple of components that each of them should have different layout/ui (templates) conditioned with display dimensions.

My solution is to create such a component:

import {Component} from '@angular/core';
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';

@Component({
    selector: 'ui-switcher',
    template: `
        <ng-content *ngIf="isSmall" select="mobile"></ng-content>
        <ng-content *ngIf="!isSmall" select="web"></ng-content>
`
})
export class UiSwitcherComponent {
    public isSmall: boolean;

    constructor(breakpointObserver: BreakpointObserver) {
        breakpointObserver.observe([Breakpoints.Small, Breakpoints.XSmall]).subscribe(result => {
            this.isSmall = result.matches;
        });
    }

}

and use it in this way:

<ui-switcher>
    <web>
        <!-- a ui suited for large screens -->
    </web>

    <mobile>
        <!-- a very different ui suited for small mobile screen displays-->

    </mobile>
</ui-switcher>

This solution may have some pitfalls. For example we can't use same templaterefs in <mobile> and <web> sections. (above we used #searchInput and #searchInput2).


What is the best practices for such situations?

Fartab
  • 4,725
  • 2
  • 26
  • 39

1 Answers1

1

In your example, you are just adding a CSS class if isSmall is false. You can solve this by simply having 1 input (not 2), and add the class conditionally.

So, instead of rendering conditionally 2 blocks of HTML that are identical... You render 1 block with a conditional CSS class.

Example below:

@Component({
    selector: 'ui-switcher',
    template: `
        <input class="form-control" [ngClass]="{'mr-2': !isSmall}"> 
        type="text" (keyup)="this.search(searchInput.value)">
`
})

Now, if your content would really change and you need more than simple *ngIf's... Then, a good solution is to use the in tamplate if...else or even if...elseif...else.

Reference here: How to use *ngIf else in Angular?

For more conditional Class usage, check this post: Angular: conditional class with *ngClass

Hope it helped! ;)

Update:

The OP was referring to a change that only affected the CSS class, but if you want to dynamically load a component into a block of code... I would say that you go with ngComponentOutlet.

Example:

        <fieldset *ngFor="let component of components">
            <ng-container *ngComponentOutlet="component.name;
                                ngModuleFactory: dynamicComponentsModule;"></ng-container>
        </fieldset>

The good thing about this approach is that you could created a map, and for each option you have a Component associated with it. Example:

map = [
   'option1': ComponentForOption1,
   'option2': ComponentForOption2
];

I would suggest this post that provides more a complete example:

Dynamic template based on value rather than variable with ngTemplateOutlet

With this, in this answer, I provided information on how to have:

  1. Dynamic CSS classes
  2. Conditional HTML with in-template if...elseif...else
  3. Dynamic component loading
SrAxi
  • 19,787
  • 11
  • 46
  • 65
  • No, changes are more than just a css class. Suppose we have many layout changes that considering it in all components are cumbersome. We like to handle it in a single component. – Fartab Apr 30 '18 at 03:59
  • @Fartab Hey! I have updated my answer with an explanation on how to load component dynamically. If something is not clear let me know. Cheers! :D – SrAxi Apr 30 '18 at 06:05