2

I have a directive that implements a slider when you hover the element, If you visit this site when you hover the image the directive makes other images absolute to the main one and enables arrows for sliding to next image, The only problem is that i have a appLazyLoadWithLoading directive that loads images when they are visible in the page and are not in offscreen and adds loading before load and I'm looking for a way to add my directive to created img elements.

let img = this.renderer2.createElement('img');
this.renderer2.setAttribute(img, "src", this.thumbnailMaker(element.url));
this.renderer2.setAttribute(img, "alt", element.name);
this.renderer2.setAttribute(img, "title", element.name);
this.renderer2.appendChild(this.el.nativeElement.parentElement, img);

this way the img element is being added but i cant add my directive to it tryed this way and $compile and they didnt work.

this.renderer.setAttribute(img, "appLazyLoadWithLoading", "work please!");
Behnam Aminazad
  • 411
  • 2
  • 5
  • 19
  • You can not add directives on top of DOM dynamically, as of now that's not possible. One possible solution can be, create a component with selector `[appLazyLoadWithLoading]` and convert it to Angular Elements. So as soon as you add this to DOM, the specific web component created using Angular Element will kick in. I've not given a try to this, but this should work I believe – Pankaj Parkar Jul 31 '21 at 11:53
  • @PankajParkar so there's no way to do that ? Maybe writing the Img tag in HTML and then adding that to the parent element using Renderer2 ? – Behnam Aminazad Jul 31 '21 at 11:58
  • Can you please look at my last edited comment? I suggested one solution, that should work. – Pankaj Parkar Jul 31 '21 at 11:59
  • @PankajParkar Thanks I'm going to give a try and report the result here – Behnam Aminazad Jul 31 '21 at 12:00
  • Awesome, let me know how it goes, Thanks :) – Pankaj Parkar Jul 31 '21 at 12:01
  • @PankajParkar It worked like a charm, You really helped me a lot the least i can do is accept your answer if you add your answer to my question. – Behnam Aminazad Aug 01 '21 at 05:56

2 Answers2

2

It is possible not using Renderer2 but by using dynamic component loading.

Basically, instead of creating an img html element, create a component which includes an img element inside it, with whatever directives you want, and then load that component dynamically.

Here's an example StackBlitz

Aviad P.
  • 32,036
  • 14
  • 103
  • 124
1

At moment till Angular v12, you can not add components dynamically in DOM.

A solution Can be,

  1. Create a component with selector [appLazyLoadWithLoading]
  2. Convert this component to Angular Elements.
  3. Now you can use converted components dynamically.

Basically what happens is Angular Element help to covert your components to Web Component. So when you add a particular selector to DOM, the specific web component will kick in, and you will see desired behavior on HTML.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • You can add components, but not directives. – Aviad P. Aug 01 '21 at 09:06
  • Indirectly you can, component with `template: ''` (Directive is component without template), but to avoid confusion let me keep it as a component only. Thanks for the heads up @AviadP. – Pankaj Parkar Aug 01 '21 at 09:08
  • I mean you can add components dynamically, look at my answer and stackblitz - unless I misunderstand your meaning – Aviad P. Aug 01 '21 at 09:09
  • @AviadP. yes, I saw your answer. We can add components dynamically in [multiple ways](https://www.youtube.com/watch?v=-8GG8wJmPGI). I think you misunderstood, In this case, OP wants to add something on top of DOM which itself created on the fly programmatically, in that case, it won't possible. I can see Angular Elements is the way to go for this. – Pankaj Parkar Aug 01 '21 at 09:15
  • I don't see why adding a component using a component factory wouldn't work for the OP – Aviad P. Aug 01 '21 at 09:20
  • Let me try to explain here, there OP creates `img` tag on top of that OP wanted to add `appLazyLoadWithLoading` directive, that's not working for him. When you want to load something dynamically using `ComponetFactoryResolver`, it requires a hold of a template (`ViewContainerRef`) inside the component, so that you can call `createComponent` method on it. Now my question to you is, how would you do the same thing on `img` tag here? – Pankaj Parkar Aug 01 '21 at 09:25
  • @AviadP. One workaround could add `img` element first hand(what you've suggested), but the logic could be anything like `img`/`p` tag or any reusable plugin that can be introduced to manipulate DOM, which is used throughout the organization. I've also seen this kind of scenario before too. I hope I've shared my thought process behind suggesting the way. Thanks – Pankaj Parkar Aug 01 '21 at 09:38
  • The OP calls `appendChild` on `this.el...` instead of doing that, he can put a template ref there and instantiate a dynamic component inside it – Aviad P. Aug 01 '21 at 09:42
  • I already mentioned the same in my last comment, please check, cheers – Pankaj Parkar Aug 01 '21 at 09:54
  • See my updated [stackblitz](https://stackblitz.com/edit/angular-ivy-tebr2e?file=src/app/app.component.ts) - it does exactly what the op wants, creates an image dynamically with a directive – Aviad P. Aug 01 '21 at 10:42