@@ -77,6 +77,9 @@ Directive.prototype._bind = function () {
7777 _ . extend ( this , def )
7878 }
7979
80+ // setup directive params
81+ this . _setupParams ( )
82+
8083 // initial bind
8184 if ( this . bind ) {
8285 this . bind ( )
@@ -131,6 +134,65 @@ Directive.prototype._bind = function () {
131134 this . _bound = true
132135}
133136
137+ /**
138+ * Setup all param attributes, e.g. track-by,
139+ * transition-mode, etc...
140+ */
141+
142+ Directive . prototype . _setupParams = function ( ) {
143+ if ( ! this . params ) {
144+ return
145+ }
146+ var params = this . params
147+ // swap the params array with a fresh object.
148+ this . params = Object . create ( null )
149+ var i = params . length
150+ var key , val , mappedKey
151+ while ( i -- ) {
152+ key = params [ i ]
153+ mappedKey = _ . camelize ( key )
154+ val = _ . attr ( this . el , key )
155+ if ( val != null ) {
156+ // static
157+ this . params [ mappedKey ] = val === '' ? true : val
158+ } else {
159+ // dynamic
160+ val = _ . getBindAttr ( this . el , key )
161+ if ( val != null ) {
162+ this . _setupParamWatcher ( mappedKey , val )
163+ }
164+ }
165+ }
166+ }
167+
168+ /**
169+ * Setup a watcher for a dynamic param.
170+ *
171+ * @param {String } key
172+ * @param {String } expression
173+ */
174+
175+ Directive . prototype . _setupParamWatcher = function ( key , expression ) {
176+ var self = this
177+ var called = false
178+ var unwatch = ( this . _scope || this . vm ) . $watch ( expression , function ( val , oldVal ) {
179+ self . params [ key ] = val
180+ // since we are in immediate mode,
181+ // only call the param change callbacks if this is not the first update.
182+ if ( called ) {
183+ var cb = self . paramWatchers && self . paramWatchers [ key ]
184+ if ( cb ) {
185+ cb . call ( self , val , oldVal )
186+ }
187+ } else {
188+ called = true
189+ }
190+ } , {
191+ immediate : true
192+ } )
193+ ; ( this . _paramUnwatchFns || ( this . _paramUnwatchFns = [ ] ) ) . push ( unwatch )
194+ }
195+
134196/**
135197 * Check if the directive is a function caller
136198 * and if the expression is a callable one. If both true,
@@ -161,30 +223,6 @@ Directive.prototype._checkStatement = function () {
161223 }
162224}
163225
164- /**
165- * Check for an attribute directive param, e.g. lazy
166- *
167- * @param {String } name
168- * @return {String }
169- */
170-
171- Directive . prototype . param = function ( name ) {
172- var param = _ . attr ( this . el , name )
173- if ( param != null ) {
174- param = ( this . _scope || this . vm ) . $interpolate ( param )
175- } else {
176- param = _ . getBindAttr ( this . el , name )
177- if ( param != null ) {
178- param = ( this . _scope || this . vm ) . $eval ( param )
179- process . env . NODE_ENV !== 'production' && _ . log (
180- 'You are using bind- syntax on "' + name + '", which ' +
181- 'is a directive param. It will be evaluated only once.'
182- )
183- }
184- }
185- return param
186- }
187-
188226/**
189227 * Set the corresponding value with the setter.
190228 * This should only be used in two-way directives
@@ -253,13 +291,21 @@ Directive.prototype._teardown = function () {
253291 this . _watcher . teardown ( )
254292 }
255293 var listeners = this . _listeners
294+ var i
256295 if ( listeners ) {
257- for ( var i = 0 ; i < listeners . length ; i ++ ) {
296+ i = listeners . length
297+ while ( i -- ) {
258298 _ . off ( this . el , listeners [ i ] [ 0 ] , listeners [ i ] [ 1 ] )
259299 }
260300 }
261- this . vm = this . el =
262- this . _watcher = this . _listeners = null
301+ var unwatchFns = this . _paramUnwatchFns
302+ if ( unwatchFns ) {
303+ i = unwatchFns . length
304+ while ( i -- ) {
305+ unwatchFns [ i ] ( )
306+ }
307+ }
308+ this . vm = this . el = this . _watcher = this . _listeners = null
263309 }
264310}
265311
0 commit comments