4

I have a component toolbar with template:

<div *ngFor="let item of items" class="toolbar__item">
  <a href="{{ item.url }}" [attributes]="item.attributes">{{ item.label }}</a>
</div>

I want to bind an array of item.options to an A element. How to do it with Angular 5?

const items = [
  { 'url': 'someurl', 'label': 'Label', 'attributes': {'data-target': '#dropdown', 'data-toggle': 'dropdown'} }
]
Anthony
  • 463
  • 5
  • 8
  • You could create a [Directive](https://angular.io/guide/attribute-directives). Anchors do not have any such property ordinarily. However, this seems confusing and I'd suggest thinking over your reasons for wanting it. Or... are you trying to set the corresponding attributes dynamically on the target? It is unclear. – Aluan Haddad Apr 11 '18 at 06:43
  • Thank you for answer. Why it seems confusing to you? Imagine a toolbar with multiple buttons: one button triggers a dropdown menu and other one triggers a sidebar navigation. So I need different data attributes to be set for them. – Anthony Apr 11 '18 at 06:57
  • So options are just attributes? If they are, call them attributes! – Aluan Haddad Apr 11 '18 at 06:59
  • Yes, options are just data-attributes. I expect to get a result HTML as `Label` – Anthony Apr 11 '18 at 07:02
  • Well, that's not supported syntactically by Angular but you could presumably create a directive that worked that way. Please fix your naming. If you used the sensible name, we could have saved significant time. – Aluan Haddad Apr 11 '18 at 07:03
  • Naming fixed. So, maybe right way is bind event handler instead of data-attributes. For example: ` – Anthony Apr 11 '18 at 07:17
  • I'm glad that you fixed the name, it is already far clearer. I don't think event handling makes sense at all. You are trying to set attributes dynamically. I don't see how they are equivalent. – Aluan Haddad Apr 11 '18 at 07:22

1 Answers1

4

I expect you could create a directive that would store and assign dynamic attributes to an element but I've not tested it.

import {Directive, ElementRef, Input} from '@angular/core';

@Directive({
  selector: '[dynamicAttributes]'
})
export class DynamicAttributesDirective {
  @Input() dynamicAttributes: {[key: string]: string};

  constructor(public element: ElementRef<HTMLElement>) {}

  ngOnInit() {
    Object.assign(this.element.nativeElement.attributes, this.dynamicAttributes)
  }
}

And you would consume it as follows

<a href="{{item.url}}" [dynamicAttributes]="item.attributes">{{item.label}}</a>
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
  • Sorry, does not work. An error occurred: Can't bind to 'dynamicAttributes' since it isn't a known property of 'a'. Directive has been attached in @NgModule declarations of app.module.ts file – Anthony Apr 11 '18 at 09:56
  • @karminski did you add it to an `NgModule`? You have to do that because Angular does not do any dependency analysis (you must explicitly register everything). Directives, like Components, go in `declarations`. – Aluan Haddad Apr 11 '18 at 09:57
  • yes I do that. If rename `dynamicAttributes` to `appAttributes` an error disappears, but attributes does not append to an element. – Anthony Apr 11 '18 at 10:03
  • Sorry, had a typo. The name of the property and the directive need to match and now they do. Use `[dynamicAttributes]`. – Aluan Haddad Apr 11 '18 at 10:04
  • Ok. It rendered as `Label` :) – Anthony Apr 11 '18 at 10:08
  • I do not follow – Aluan Haddad Apr 11 '18 at 10:10