|
10 | 10 | import {assertIndexInRange} from '../../util/assert'; |
11 | 11 | import {isObservable} from '../../util/lang'; |
12 | 12 | import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; |
13 | | -import {GlobalTargetResolver, isProceduralRenderer, Renderer3} from '../interfaces/renderer'; |
| 13 | +import {GlobalTargetResolver, Renderer} from '../interfaces/renderer'; |
14 | 14 | import {RElement} from '../interfaces/renderer_dom'; |
15 | 15 | import {isDirectiveHost} from '../interfaces/type_checks'; |
16 | 16 | import {CLEANUP, CONTEXT, LView, RENDERER, TView} from '../interfaces/view'; |
@@ -114,7 +114,7 @@ function findExistingListener( |
114 | 114 | } |
115 | 115 |
|
116 | 116 | function listenerInternal( |
117 | | - tView: TView, lView: LView<{}|null>, renderer: Renderer3, tNode: TNode, eventName: string, |
| 117 | + tView: TView, lView: LView<{}|null>, renderer: Renderer, tNode: TNode, eventName: string, |
118 | 118 | listenerFn: (e?: any) => any, useCapture: boolean, |
119 | 119 | eventTargetResolver?: GlobalTargetResolver): void { |
120 | 120 | const isTNodeDirectiveHost = isDirectiveHost(tNode); |
@@ -145,53 +145,45 @@ function listenerInternal( |
145 | 145 |
|
146 | 146 | // In order to match current behavior, native DOM event listeners must be added for all |
147 | 147 | // events (including outputs). |
148 | | - if (isProceduralRenderer(renderer)) { |
149 | | - // There might be cases where multiple directives on the same element try to register an event |
150 | | - // handler function for the same event. In this situation we want to avoid registration of |
151 | | - // several native listeners as each registration would be intercepted by NgZone and |
152 | | - // trigger change detection. This would mean that a single user action would result in several |
153 | | - // change detections being invoked. To avoid this situation we want to have only one call to |
154 | | - // native handler registration (for the same element and same type of event). |
155 | | - // |
156 | | - // In order to have just one native event handler in presence of multiple handler functions, |
157 | | - // we just register a first handler function as a native event listener and then chain |
158 | | - // (coalesce) other handler functions on top of the first native handler function. |
159 | | - let existingListener = null; |
160 | | - // Please note that the coalescing described here doesn't happen for events specifying an |
161 | | - // alternative target (ex. (document:click)) - this is to keep backward compatibility with the |
162 | | - // view engine. |
163 | | - // Also, we don't have to search for existing listeners is there are no directives |
164 | | - // matching on a given node as we can't register multiple event handlers for the same event in |
165 | | - // a template (this would mean having duplicate attributes). |
166 | | - if (!eventTargetResolver && isTNodeDirectiveHost) { |
167 | | - existingListener = findExistingListener(tView, lView, eventName, tNode.index); |
168 | | - } |
169 | | - if (existingListener !== null) { |
170 | | - // Attach a new listener to coalesced listeners list, maintaining the order in which |
171 | | - // listeners are registered. For performance reasons, we keep a reference to the last |
172 | | - // listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through |
173 | | - // the entire set each time we need to add a new listener. |
174 | | - const lastListenerFn = (<any>existingListener).__ngLastListenerFn__ || existingListener; |
175 | | - lastListenerFn.__ngNextListenerFn__ = listenerFn; |
176 | | - (<any>existingListener).__ngLastListenerFn__ = listenerFn; |
177 | | - processOutputs = false; |
178 | | - } else { |
179 | | - listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */); |
180 | | - const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn); |
181 | | - ngDevMode && ngDevMode.rendererAddEventListener++; |
182 | | - |
183 | | - lCleanup.push(listenerFn, cleanupFn); |
184 | | - tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1); |
185 | | - } |
186 | 148 |
|
| 149 | + // There might be cases where multiple directives on the same element try to register an event |
| 150 | + // handler function for the same event. In this situation we want to avoid registration of |
| 151 | + // several native listeners as each registration would be intercepted by NgZone and |
| 152 | + // trigger change detection. This would mean that a single user action would result in several |
| 153 | + // change detections being invoked. To avoid this situation we want to have only one call to |
| 154 | + // native handler registration (for the same element and same type of event). |
| 155 | + // |
| 156 | + // In order to have just one native event handler in presence of multiple handler functions, |
| 157 | + // we just register a first handler function as a native event listener and then chain |
| 158 | + // (coalesce) other handler functions on top of the first native handler function. |
| 159 | + let existingListener = null; |
| 160 | + // Please note that the coalescing described here doesn't happen for events specifying an |
| 161 | + // alternative target (ex. (document:click)) - this is to keep backward compatibility with the |
| 162 | + // view engine. |
| 163 | + // Also, we don't have to search for existing listeners is there are no directives |
| 164 | + // matching on a given node as we can't register multiple event handlers for the same event in |
| 165 | + // a template (this would mean having duplicate attributes). |
| 166 | + if (!eventTargetResolver && isTNodeDirectiveHost) { |
| 167 | + existingListener = findExistingListener(tView, lView, eventName, tNode.index); |
| 168 | + } |
| 169 | + if (existingListener !== null) { |
| 170 | + // Attach a new listener to coalesced listeners list, maintaining the order in which |
| 171 | + // listeners are registered. For performance reasons, we keep a reference to the last |
| 172 | + // listener in that list (in `__ngLastListenerFn__` field), so we can avoid going through |
| 173 | + // the entire set each time we need to add a new listener. |
| 174 | + const lastListenerFn = (<any>existingListener).__ngLastListenerFn__ || existingListener; |
| 175 | + lastListenerFn.__ngNextListenerFn__ = listenerFn; |
| 176 | + (<any>existingListener).__ngLastListenerFn__ = listenerFn; |
| 177 | + processOutputs = false; |
187 | 178 | } else { |
188 | | - listenerFn = wrapListener(tNode, lView, context, listenerFn, true /** preventDefault */); |
189 | | - target.addEventListener(eventName, listenerFn, useCapture); |
| 179 | + listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */); |
| 180 | + const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn); |
190 | 181 | ngDevMode && ngDevMode.rendererAddEventListener++; |
191 | 182 |
|
192 | | - lCleanup.push(listenerFn); |
193 | | - tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCapture); |
| 183 | + lCleanup.push(listenerFn, cleanupFn); |
| 184 | + tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1); |
194 | 185 | } |
| 186 | + |
195 | 187 | } else { |
196 | 188 | // Even if there is no native listener to add, we still need to wrap the listener so that OnPush |
197 | 189 | // ancestors are marked dirty when an event occurs. |
|
0 commit comments