HTML attribute vs DOM properties

2023-05-24
javascript/html/css

Q. 앵귤러 템플릿에서 input disabled을 동적 처리하고 싶어요.

// ts
isDisabled = true;
<div class="item_radio" *ngFor="let item of list">
  <input
    type="radio"
    id="type{{ item.value }}"
    class="inp_radio"
    name="type"
    formControlName="type"
    [value]="item.value"
    [disabled]="isDisabled"
  />
  ...
</div>

결과적으로 위 코드는 disabled를 동적 처리하지 못한다. 실제 DOM 트리의 해당 요소를 보면 disabled 대신 ng-reflect-is-disabled="true"만 생성되어 있다. ng-reflect-is-disabled는 앵귤러 프로덕션 빌드에서는 보이지 않는 단순 디버깅용으로 쓰이는 요소로, 결국 disabled 처리는 되지 않는다.

아래는 이 현상에 대해 앵귤러팀이 해준 답변이다.


This is working as designed. Binding syntax (using square brackets [disabled]) binds an expression to a DOM property, not an attribute. Static values are added to elements as attributes, hence the difference between input disabled and input [disabled]. The ng-reflect-is-disabled is for debugging purposes and will not be present in production.

If you need to set the disabled attribute, using [attr.disabled] is the correct way to go here.

[disabled]="" 혹은 disabled="{{}}" 문법은 attribute가 아닌 DOM property로 바인딩되므로 이것이 올바른 동작이라고 한다. 따라서 attribute에 직접 바인딩하는 [attr.disabled] 를 쓰라고 권장한다.

그렇다면 attribute와 property의 차이는 무엇인가?


1. attribute vs property


2. 음… 그래서 [disabled]="“가 동작하지 않은 이유?

disabled는 input태그의 표준 attribute이므로 property로도 접근 가능하다. 그래서 앵귤러쪽의 답변이 썩 속시원하지가 않았다. 표준 태그니까 property 바인딩이 되어야 하는 것 아니야? 그래서 더 찾아보니 아래의 두 글을 발견했다.

결론만 말하면 ReactiveFormsModule(ex. formControl)은 [disabled] 바인딩을 함께 사용할 수 없다. 앵귤러에서는 반응형 폼 모듈을 쓸 때 disabled를 아래처럼 동작시키기를 권장하고 있다.


// 폼컨트롤에 disabled 옵션 처리
formBuilder.control({value: "ALL", disabled: true});

// 메서드를 통해 disabled 제어
form.controls["id"].enabled();
form.controls["id"].disabled();

즉, 반응형 폼은 formBuilder를 통해 만들어지므로 FormControlState 옵션에 disabled 속성을 지정하지 않으면, HTML attribute 자체가 생기지 않는 것이다. 그러면 당연히 DOM에도 없으니 property 접근도 불가하다. 이런 내용을 앵귤러 측에서 다 생략해버려서 속시원하지가 않았던 거라고!


3. formControl을 템플릿 기반으로 disable 처리하려면?

이벤트 기반이 아니라 모종의 이유(초기에만 disabled 처리를 한다든지)로 enable/disable 메서드로 제어하고 싶지 않을 때는, 여전히 template-driven한 방식으로 disabled 처리를 할 수 있다.

바로 [attr.disabled]이다. 이건 아예 disabled라는 속성을 DOM에 직접 만들어주고 직접 제어하는 것이므로 지정한 formControl과는 상관 없이 동작할 수 있다.


4. 결론

Typescript mixins in Angular

2022-01-16
javascript/html/css

Rxjs marble testing with jasmine-marbles

2020-08-09
javascript/html/css

Closure, especially in javascript

2020-04-18
javascript/html/css
comments powered by Disqus