#@if() + Directive

26 messages · Page 1 of 1 (latest)

crystal drift
#

Is there any way of showing an element based on some Directive?

const CUSTOM_BREAKPOINTS = {
  small: '(max-width: 1999px)'
};

@Directive({
  selector: '[appResponsive]',
  standalone: true,
  host: {
    '[class.mobile]': 'isMobile'
  }
})
export class MobileClassDirective implements OnDestroy {
  isMobile = false;
  private destroy$ = new Subject<void>();

  constructor(private breakpointObserver: BreakpointObserver) {
    this.breakpointObserver
      .observe([CUSTOM_BREAKPOINTS.small])
      .pipe(takeUntil(this.destroy$))
      .subscribe(result => {
        this.isMobile = result.matches;
      });
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

// HTML
  <div class="taglist-search" appResponsive> // Dynamic class added properly based on viewport
    @if (!appResponsive.isMobile) {<ng-container *ngTemplateOutlet="taglist"></ng-container>} // doesn't work ofc, but is there any way to get a similar behaviour?
#

I've been reading exportAs but even with it I can't seem to make it work, but the isMobile prop is public by default right?

jade jolt
#

Show us what you tried with exportAs. (And use takeUntilDestroyed() instead of reinventing it). Yes, all properties are public by default in TypeScript.

crystal drift
jade jolt
#

No. @let won't have access to a directive set on another HTML element. You can use #responsive="appResponsive" because on this specific HTML element, the appResponsive directive is used and is exported as appResponsive.

crystal drift
#

I'm still failing to see what's the advange of directives is, so far in every example I've tried they can be replaced easily with a class

#

In this case if I use [class.mobile]="isMobile" and move my Directive logic to the component it works

#

Maybe I can't see the advantage because I only have a single component in my code and the directive becomes helpful with more components? What I'm trying to do is to have a global way to add a class to an element based on the viewport

jade jolt
#

But using JavaScript to put a CSS class based on whether CSS tells you if you are under a breakpoint or not is quite weird. You could do that in plain CSS directly.

crystal drift
#

Honestly the problem I'm trying to solve can be fixed with grid easily

#

I'm trying to apply the concepts I learned on Udemy, Ninja Book and Documentation to an existing project

#

That is: display the taglist in two different places based on the viewport

#

And apply different styles both to .taglist-search and to .taglist based on some other over-complex CSS so that I can learn and use :has and :not pseudo selectors

crystal drift
jade jolt
#

Yes. You'll need to pass a DestroyRef as argument if you use it outside of a dependency injection context (i.e. outside of the constructor, for a component or directive or pipe or service)

crystal drift
#

Yes I read that part, and internally it uses the new inject()

#

I never wanted to dig rxjs it looks way too complex for my n00b mind 😭

jade jolt
#

That said, you shouldn't even subscribe here. Instead, you should make isMobile a signal, and use toSignal() to transform the observable into a signal (and automatically unsubscribe)

crystal drift
#

I didn't start learning signals yet

#

I really don't like the () needed on every call in the template part

#

But yeah I can see the advantages of using them in this case

jade jolt
#

You'd better learn them fast. They're at the core of Angular now. Plain inputs are signals for example.

crystal drift
#

I know but we've just migrated from v12 to v18 and there are so many things to learn

#

I'm following a course and I discovered I knew like 20% of Angular, despite working with it for 4 years now