0

I have a simple angular app with a module and a component. For the sake of simplicity let us assume that the component ts and the template file is like the following snippet

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

import {
  ChildComponent
} from './child/child.component';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'test-app';
  val;
  clickEvt() {
    alert("clicked")
  }

  isTruthy() {
    if (( < HTMLInputElement > document.getElementById("inp1")).value == "admin" && ( < HTMLInputElement > document.getElementById("inp2")).value == "admin") {
      return true;
    }
    return false;
  }

  ngOnInit() {
    this.val = {};
    this.val.id = "id1";
    this.val.class = "abc";
  }
}
<label>User</label>
<input {{...val}} (input)="isTruthy()" />
<br>
<label>Password</label>
<input id="inp2" (input)="isTruthy()" />
<button (click)="clickEvt()">Login</button>
<div *ngIf="isTruthy(); then truthy else falsey"></div>
<ng-template #truthy>
  <h1>Success</h1>
  <child-component [value]="isTruthy()"></child-component>
</ng-template>
<ng-template #falsey>
  <h1>Failure</h1>
  <child-component [value]="isTruthy()"></child-component>
</ng-template>

In the HTML template, you can notice me trying to use {{ ...val }}. This is my attempt to use spread operator in the template but unfortunately I get the exception

ERROR DOMException: Failed to execute 'setAttribute' on 'Element': '{{...val.id}}' is not a valid attribute name.

I just want to know, is there a way to use spread operator or is there an equivalent way in angular to give multiple attributes in one go which is obtained from a variable?

3
  • 1
    I do get a bit worried when people down vote without providing any valid reason Commented Sep 26, 2019 at 13:03
  • see Maryannah's answer. you can also <input [id]="val.id" [ngClass]="val.class" (input)="isTruthy()" /> Commented Sep 26, 2019 at 13:03
  • @Eliseo, your approach would be tedious because, I may have more attributes than just id and className Commented Sep 26, 2019 at 13:05

2 Answers 2

1

No, you cannot use the spread in a template (even less like you're trying).

To achieve that, you will need a reference to your template.

<input #myInput (input)="isTruthy()" />
@ViewChild('myInput', { static: true }) myInput: ElementRef<HTMLInputElement>;

ngOnInit() {
  Object.assign(this.myInput.nativeElement, this.val);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Just an addition, incase of using conditional rendering like *ngIf, the value { static: true } should be set to false or else the value of myInput would be undefined at the time of assignment.
1

One way to do this could be create a directive like

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

@Directive({
  selector: '[setAttr]'
})
export class AttrDirective {

  constructor(private el: ElementRef) { }

  @Input() attr: any;

  ngOnInit(){
    if(this.attr){
       console.log(this.el.nativeElement)
      Object.keys(this.attr).forEach(k=>{
        this.el.nativeElement.setAttribute(k,this.attr[k])
      console.log(this.el.nativeElement)
      })
    }
  }
}

then apply on input like

<input type="text" setAttr [attr]="val">

demo

2 Comments

For future reference, Object.keys.forEach is the old way. Now you have Object.assign and spread with obj = { ...obj, ...newObj }.
FYI Angular will not keep your attributes updated if properties inside of the attr object are changed. The only Angular binding occurs at the top level attr object. For that reason, we abandoned this approach and now just write out all the properties longhand.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.