Skip to content

Commit d5a12d5

Browse files
marclavalmhevery
authored andcommitted
feat(ng-if): an implementation of ng-if
Closes angular#317
1 parent 368cc29 commit d5a12d5

2 files changed

Lines changed: 247 additions & 0 deletions

File tree

modules/directives/src/ng_if.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {Template} from 'core/annotations/annotations';
2+
import {OnChange} from 'core/compiler/interfaces';
3+
import {ViewPort} from 'core/compiler/viewport';
4+
import {isBlank} from 'facade/lang';
5+
6+
@Template({
7+
selector: '[ng-if]',
8+
bind: {
9+
'ng-if': 'condition'
10+
}
11+
})
12+
export class NgIf {
13+
viewPort: ViewPort;
14+
prevCondition: boolean;
15+
16+
constructor(viewPort: ViewPort) {
17+
this.viewPort = viewPort;
18+
this.prevCondition = null;
19+
}
20+
21+
set condition(newCondition) {
22+
if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
23+
this.prevCondition = true;
24+
this.viewPort.create();
25+
} else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
26+
this.prevCondition = false;
27+
this.viewPort.clear();
28+
}
29+
}
30+
}
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import {describe, xit, it, expect, beforeEach, ddescribe, iit, IS_DARTIUM} from 'test_lib/test_lib';
2+
3+
import {DOM} from 'facade/dom';
4+
5+
import {Injector} from 'di/di';
6+
import {Lexer, Parser, ChangeDetector} from 'change_detection/change_detection';
7+
8+
import {Compiler, CompilerCache} from 'core/compiler/compiler';
9+
import {DirectiveMetadataReader} from 'core/compiler/directive_metadata_reader';
10+
11+
import {Component} from 'core/annotations/annotations';
12+
import {TemplateConfig} from 'core/annotations/template_config';
13+
14+
import {NgIf} from 'directives/ng_if';
15+
16+
export function main() {
17+
describe('ng-if', () => {
18+
var view, cd, compiler, component;
19+
beforeEach(() => {
20+
compiler = new Compiler(null, new DirectiveMetadataReader(), new Parser(new Lexer()), new CompilerCache());
21+
});
22+
23+
function createElement(html) {
24+
return DOM.createTemplate(html).content.firstChild;
25+
}
26+
27+
function createView(pv) {
28+
component = new TestComponent();
29+
view = pv.instantiate(null);
30+
view.hydrate(new Injector([]), null, component);
31+
cd = view.changeDetector;
32+
}
33+
34+
function compileWithTemplate(template) {
35+
return compiler.compile(TestComponent, createElement(template));
36+
}
37+
38+
it('should work in a template attribute', (done) => {
39+
compileWithTemplate('<div><copy-me template="ng-if booleanCondition">hello</copy-me></div>').then((pv) => {
40+
createView(pv);
41+
cd.detectChanges();
42+
43+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
44+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
45+
done();
46+
});
47+
});
48+
49+
it('should work in a template element', (done) => {
50+
compileWithTemplate('<div><template [ng-if]="booleanCondition"><copy-me>hello2</copy-me></template></div>').then((pv) => {
51+
createView(pv);
52+
cd.detectChanges();
53+
54+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
55+
expect(DOM.getText(view.nodes[0])).toEqual('hello2');
56+
done();
57+
});
58+
});
59+
60+
it('should toggle node when condition changes', (done) => {
61+
compileWithTemplate('<div><copy-me template="ng-if booleanCondition">hello</copy-me></div>').then((pv) => {
62+
createView(pv);
63+
64+
component.booleanCondition = false;
65+
cd.detectChanges();
66+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
67+
expect(DOM.getText(view.nodes[0])).toEqual('');
68+
69+
70+
component.booleanCondition = true;
71+
cd.detectChanges();
72+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
73+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
74+
75+
component.booleanCondition = false;
76+
cd.detectChanges();
77+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
78+
expect(DOM.getText(view.nodes[0])).toEqual('');
79+
80+
done();
81+
});
82+
});
83+
84+
it('should update several nodes with ng-if', (done) => {
85+
var templateString =
86+
'<div>' +
87+
'<copy-me template="ng-if numberCondition + 1 >= 2">helloNumber</copy-me>' +
88+
'<copy-me template="ng-if stringCondition == \'foo\'">helloString</copy-me>' +
89+
'<copy-me template="ng-if functionCondition(stringCondition, numberCondition)">helloFunction</copy-me>' +
90+
'</div>';
91+
compileWithTemplate(templateString).then((pv) => {
92+
createView(pv);
93+
94+
cd.detectChanges();
95+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(3);
96+
expect(DOM.getText(view.nodes[0])).toEqual('helloNumberhelloStringhelloFunction');
97+
98+
component.numberCondition = 0;
99+
cd.detectChanges();
100+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
101+
expect(DOM.getText(view.nodes[0])).toEqual('helloString');
102+
103+
component.numberCondition = 1;
104+
component.stringCondition = "bar";
105+
cd.detectChanges();
106+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
107+
expect(DOM.getText(view.nodes[0])).toEqual('helloNumber');
108+
done();
109+
});
110+
});
111+
112+
113+
if (!IS_DARTIUM) {
114+
it('should leave the element if the condition is a non-empty string (JS)', (done) => {
115+
compileWithTemplate('<div><copy-me template="ng-if stringCondition">hello</copy-me></div>').then((pv) => {
116+
createView(pv);
117+
cd.detectChanges();
118+
119+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
120+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
121+
done();
122+
});
123+
});
124+
125+
it('should leave the element if the condition is an object (JS)', (done) => {
126+
compileWithTemplate('<div><copy-me template="ng-if objectCondition">hello</copy-me></div>').then((pv) => {
127+
createView(pv);
128+
cd.detectChanges();
129+
130+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
131+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
132+
done();
133+
});
134+
});
135+
136+
it('should remove the element if the condition is null (JS)', (done) => {
137+
compileWithTemplate('<div><copy-me template="ng-if nullCondition">hello</copy-me></div>').then((pv) => {
138+
createView(pv);
139+
cd.detectChanges();
140+
141+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
142+
expect(DOM.getText(view.nodes[0])).toEqual('');
143+
done();
144+
});
145+
});
146+
147+
it('should not add the element twice if the condition goes from true to true (JS)', (done) => {
148+
compileWithTemplate('<div><copy-me template="ng-if numberCondition">hello</copy-me></div>').then((pv) => {
149+
createView(pv);
150+
151+
cd.detectChanges();
152+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
153+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
154+
155+
component.numberCondition = 2;
156+
cd.detectChanges();
157+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(1);
158+
expect(DOM.getText(view.nodes[0])).toEqual('hello');
159+
160+
done();
161+
});
162+
});
163+
164+
it('should not recreate the element if the condition goes from true to true (JS)', (done) => {
165+
compileWithTemplate('<div><copy-me template="ng-if numberCondition">hello</copy-me></div>').then((pv) => {
166+
createView(pv);
167+
168+
cd.detectChanges();
169+
DOM.addClass(view.nodes[0].childNodes[1], "foo");
170+
171+
component.numberCondition = 2;
172+
cd.detectChanges();
173+
expect(DOM.hasClass(view.nodes[0].childNodes[1], "foo")).toBe(true);
174+
175+
done();
176+
});
177+
});
178+
} else {
179+
it('should not create the element if the condition is not a boolean (DART)', (done) => {
180+
compileWithTemplate('<div><copy-me template="ng-if numberCondition">hello</copy-me></div>').then((pv) => {
181+
createView(pv);
182+
expect(function(){cd.detectChanges();}).toThrowError();
183+
expect(view.nodes[0].querySelectorAll('copy-me').length).toEqual(0);
184+
expect(DOM.getText(view.nodes[0])).toEqual('');
185+
done();
186+
});
187+
});
188+
}
189+
190+
});
191+
}
192+
193+
@Component({
194+
selector: 'test-cmp',
195+
template: new TemplateConfig({
196+
inline: '', // each test swaps with a custom template.
197+
directives: [NgIf]
198+
})
199+
})
200+
class TestComponent {
201+
booleanCondition: boolean;
202+
numberCondition: number;
203+
stringCondition: string;
204+
functionCondition: Function;
205+
objectCondition: any;
206+
nullCondition: any;
207+
constructor() {
208+
this.booleanCondition = true;
209+
this.numberCondition = 1;
210+
this.stringCondition = "foo";
211+
this.functionCondition = function(s, n){
212+
return s == "foo" && n == 1;
213+
};
214+
this.objectCondition = {};
215+
this.nullCondition = null;
216+
}
217+
}

0 commit comments

Comments
 (0)