fix(platform-browser): should not throw for debug attrs containing $ (#14353)

Closes #9566

PR Close #14353
This commit is contained in:
Dzmitry Shylovich 2017-02-08 14:36:43 +03:00 committed by Miško Hevery
parent e5a144d902
commit 1cfbefebe3
2 changed files with 46 additions and 1 deletions

View File

@ -1507,6 +1507,14 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
.toContain('ng-reflect-dir-prop="hello"');
});
it(`should work with prop names containing '$'`, () => {
TestBed.configureTestingModule({declarations: [ParentCmp, SomeCmpWithInput]});
const fixture = TestBed.createComponent(ParentCmp);
fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test$="hello"');
});
it('should reflect property values on template comments', () => {
TestBed.configureTestingModule({declarations: [MyComp]});
const template = '<template [ngIf]="ctxBoolProp"></template>';
@ -2300,3 +2308,16 @@ class DirectiveWithPropDecorators {
class SomeCmp {
value: any;
}
@Component({
selector: 'parent-cmp',
template: `<cmp [test$]="name"></cmp>`,
})
export class ParentCmp {
name: string = 'hello';
}
@Component({selector: 'cmp', template: ''})
class SomeCmpWithInput {
@Input() test$: any;
}

View File

@ -230,7 +230,14 @@ export class DomRenderer implements Renderer {
renderElement.nodeValue =
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2));
} else {
this.setElementAttribute(renderElement, propertyName, propertyValue);
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
if (propertyName[propertyName.length - 1] === '$') {
const attrNode: Attr = createAttrNode(propertyName).cloneNode(true) as Attr;
attrNode.value = propertyValue;
renderElement.setAttributeNode(attrNode);
} else {
this.setElementAttribute(renderElement, propertyName, propertyValue);
}
}
}
@ -341,3 +348,20 @@ export function splitNamespace(name: string): string[] {
const match = name.match(NS_PREFIX_RE);
return [match[1], match[2]];
}
let attrCache: Map<string, Attr>;
function createAttrNode(name: string): Attr {
if (!attrCache) {
attrCache = new Map<string, Attr>();
}
if (attrCache.has(name)) {
return attrCache.get(name);
} else {
const div = document.createElement('div');
div.innerHTML = `<div ${name}>`;
const attr: Attr = div.firstChild.attributes[0];
attrCache.set(name, attr);
return attr;
}
}