feat(view): adds event binding to view instantiation.
Only native non-bubbling events are supported by the commit.
This commit is contained in:
parent
bccc863567
commit
c5b0baf805
|
@ -373,6 +373,22 @@ export class ProtoView {
|
||||||
if (isPresent(elementInjector)) {
|
if (isPresent(elementInjector)) {
|
||||||
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewPort, lightDom);
|
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewPort, lightDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// events
|
||||||
|
if (isPresent(binder.events)) {
|
||||||
|
// TODO(rado): if there is directive at this element that injected an
|
||||||
|
// event emitter for that eventType do not attach the handler.
|
||||||
|
MapWrapper.forEach(binder.events, (expr, eventName) => {
|
||||||
|
DOM.on(element, eventName, (event) => {
|
||||||
|
if (event.target === element) {
|
||||||
|
// TODO(rado): replace with
|
||||||
|
// expr.eval(new ContextWithVariableBindings(view.context, {'$event': event}));
|
||||||
|
// when eval with variable bindinds works.
|
||||||
|
expr.eval(view.context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view.init(elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
view.init(elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
||||||
|
|
|
@ -422,6 +422,37 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('event handlers', () => {
|
||||||
|
var view, ctx, called;
|
||||||
|
|
||||||
|
function createViewAndContext(protoView) {
|
||||||
|
view = createView(protoView);
|
||||||
|
ctx = view.context;
|
||||||
|
called = 0;
|
||||||
|
ctx.callMe = () => called += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dispatchClick(el) {
|
||||||
|
DOM.dispatchEvent(el, DOM.createMouseEvent('click'));
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should fire on non-bubbling native events', () => {
|
||||||
|
var pv = new ProtoView(createElement('<div class="ng-binding"><div></div></div>'),
|
||||||
|
new ProtoRecordRange());
|
||||||
|
pv.bindElement(null);
|
||||||
|
pv.bindEvent('click', parser.parseBinding('callMe()', null));
|
||||||
|
createViewAndContext(pv);
|
||||||
|
|
||||||
|
dispatchClick(view.nodes[0]);
|
||||||
|
dispatchClick(view.nodes[0].firstChild);
|
||||||
|
|
||||||
|
// the bubbled event does not execute the expression.
|
||||||
|
// It is trivially passing on webkit browsers due to
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||||
|
expect(called).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('react to record changes', () => {
|
describe('react to record changes', () => {
|
||||||
var view, cd, ctx;
|
var view, cd, ctx;
|
||||||
|
|
||||||
|
@ -602,6 +633,7 @@ class MyEvaluationContext {
|
||||||
foo:string;
|
foo:string;
|
||||||
a;
|
a;
|
||||||
b;
|
b;
|
||||||
|
callMe;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.foo = 'bar';
|
this.foo = 'bar';
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe('hello world', function () {
|
||||||
it('should greet', function() {
|
it('should greet', function() {
|
||||||
browser.get(URL);
|
browser.get(URL);
|
||||||
|
|
||||||
expect(getShadowText('hello-app')).toBe('hello world!');
|
expect(getGreetingText('hello-app')).toBe('hello world!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ describe('hello world', function () {
|
||||||
it('should greet', function() {
|
it('should greet', function() {
|
||||||
browser.get(URL);
|
browser.get(URL);
|
||||||
|
|
||||||
expect(getShadowText('hello-app')).toBe('hello world!');
|
expect(getGreetingText('hello-app')).toBe('hello world!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function getShadowText(selector) {
|
function getGreetingText(selector) {
|
||||||
return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.textContent');
|
return browser.executeScript('return document.querySelector("'+selector+'").shadowRoot.firstChild.textContent');
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ import {bootstrap, Component, Decorator, TemplateConfig, NgElement} from 'core/c
|
||||||
// The template for the component.
|
// The template for the component.
|
||||||
// Expressions in the template (like {{greeting}}) are evaluated in the
|
// Expressions in the template (like {{greeting}}) are evaluated in the
|
||||||
// context of the HelloCmp class below.
|
// context of the HelloCmp class below.
|
||||||
inline: `{{greeting}} <span red>world</span>!`,
|
inline: `<div>{{greeting}} <span red>world</span>!</div>
|
||||||
|
<button (click)="changeGreeting()">change greeting</button>`,
|
||||||
// All directives used in the template need to be specified. This allows for
|
// All directives used in the template need to be specified. This allows for
|
||||||
// modularity (RedDec can only be used in this template)
|
// modularity (RedDec can only be used in this template)
|
||||||
// and better tooling (the template can be invalidated if the attribute is
|
// and better tooling (the template can be invalidated if the attribute is
|
||||||
|
@ -33,6 +34,9 @@ class HelloCmp {
|
||||||
constructor(service: GreetingService) {
|
constructor(service: GreetingService) {
|
||||||
this.greeting = service.greeting;
|
this.greeting = service.greeting;
|
||||||
}
|
}
|
||||||
|
changeGreeting() {
|
||||||
|
this.greeting = 'howdy';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decorators are light-weight. They don't allow for templates, or new
|
// Decorators are light-weight. They don't allow for templates, or new
|
||||||
|
|
|
@ -33,7 +33,15 @@ class DOM {
|
||||||
return el.querySelectorAll(selector);
|
return el.querySelectorAll(selector);
|
||||||
}
|
}
|
||||||
static on(element, event, callback) {
|
static on(element, event, callback) {
|
||||||
element.addEventListener(event, callback);
|
// due to https://code.google.com/p/dart/issues/detail?id=17406
|
||||||
|
// addEventListener misses zones so we use element.on.
|
||||||
|
element.on[event].listen(callback);
|
||||||
|
}
|
||||||
|
static dispatchEvent(el, evt) {
|
||||||
|
el.dispatchEvent(evt);
|
||||||
|
}
|
||||||
|
static createMouseEvent(eventType) {
|
||||||
|
return new MouseEvent(eventType, canBubble: true);
|
||||||
}
|
}
|
||||||
static getInnerHTML(el) {
|
static getInnerHTML(el) {
|
||||||
return el.innerHtml;
|
return el.innerHtml;
|
||||||
|
|
|
@ -24,6 +24,14 @@ export class DOM {
|
||||||
static on(el, evt, listener) {
|
static on(el, evt, listener) {
|
||||||
el.addEventListener(evt, listener, false);
|
el.addEventListener(evt, listener, false);
|
||||||
}
|
}
|
||||||
|
static dispatchEvent(el, evt) {
|
||||||
|
el.dispatchEvent(evt);
|
||||||
|
}
|
||||||
|
static createMouseEvent(eventType) {
|
||||||
|
var evt = new MouseEvent(eventType);
|
||||||
|
evt.initEvent(eventType, true, true);
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
static getInnerHTML(el) {
|
static getInnerHTML(el) {
|
||||||
return el.innerHTML;
|
return el.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue