@@ -114,28 +114,24 @@ function $InterpolateProvider() {
114
114
* result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
115
115
* trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
116
116
* provides Strict Contextual Escaping for details.
117
- * @returns {Object } An object describing the interpolation template string.
117
+ * @returns {function(context) } an interpolation function which is used to compute the
118
+ * interpolated string. The function has these parameters:
118
119
*
119
- * The properties of the returned object include:
120
- *
121
- * - `template` — `{string}` — original interpolation template string.
122
- * - `separators` — `{Array.<string>}` — array of separators extracted from the template.
123
- * - `expressions` — `{Array.<string>}` — array of expressions extracted from the template.
124
- * - `compute` — {function(Array)()} — function that when called with an array of values will
125
- * compute the result of interpolation for the given interpolation template and values.
120
+ * - `context`: evaluation context for all expressions embedded in the interpolated text
126
121
*/
127
122
function $interpolate ( text , mustHaveExpression , trustedContext ) {
128
123
var startIndex ,
129
124
endIndex ,
130
125
index = 0 ,
131
126
separators = [ ] ,
132
127
expressions = [ ] ,
128
+ parseFns = [ ] ,
133
129
textLength = text . length ,
134
130
hasInterpolation = false ,
135
131
hasText = false ,
136
- fn ,
137
132
exp ,
138
- concat = [ ] ;
133
+ concat = [ ] ,
134
+ lastValuesCache = { values : { } , results : { } } ;
139
135
140
136
while ( index < textLength ) {
141
137
if ( ( ( startIndex = text . indexOf ( startSymbol , index ) ) != - 1 ) &&
@@ -144,6 +140,7 @@ function $InterpolateProvider() {
144
140
separators . push ( text . substring ( index , startIndex ) ) ;
145
141
exp = text . substring ( startIndex + startSymbolLength , endIndex ) ;
146
142
expressions . push ( exp ) ;
143
+ parseFns . push ( $parse ( exp ) ) ;
147
144
index = endIndex + endSymbolLength ;
148
145
hasInterpolation = true ;
149
146
} else {
@@ -176,31 +173,16 @@ function $InterpolateProvider() {
176
173
if ( ! mustHaveExpression || hasInterpolation ) {
177
174
concat . length = separators . length + expressions . length ;
178
175
179
- return extend ( function interpolationFn ( scope ) {
180
- var values = [ ] ;
181
- forEach ( interpolationFn . expressions , function ( expression ) {
182
- values . push ( scope . $eval ( expression ) ) ;
183
- } ) ;
184
- return interpolationFn . compute ( values ) ;
185
- } , {
186
- exp : text , //deprecated
187
- template : text ,
188
- separators : separators ,
189
- expressions : expressions ,
190
- compute : function ( values ) {
191
- for ( var i = 0 , ii = expressions . length ; i < ii ; i ++ ) {
192
- concat [ 2 * i ] = separators [ i ] ;
193
- concat [ ( 2 * i ) + 1 ] = stringify ( values [ i ] ) ;
194
- }
195
- concat [ 2 * ii ] = separators [ ii ] ;
196
- return concat . join ( '' ) ;
176
+ var compute = function ( values ) {
177
+ for ( var i = 0 , ii = expressions . length ; i < ii ; i ++ ) {
178
+ concat [ 2 * i ] = separators [ i ] ;
179
+ concat [ ( 2 * i ) + 1 ] = values [ i ] ;
197
180
}
198
- } ) ;
199
- }
200
-
201
- function stringify ( value ) {
202
- try {
181
+ concat [ 2 * ii ] = separators [ ii ] ;
182
+ return concat . join ( '' ) ;
183
+ } ;
203
184
185
+ var stringify = function ( value ) {
204
186
if ( trustedContext ) {
205
187
value = $sce . getTrusted ( trustedContext , value ) ;
206
188
} else {
@@ -214,12 +196,59 @@ function $InterpolateProvider() {
214
196
}
215
197
216
198
return value ;
199
+ } ;
217
200
218
- } catch ( err ) {
219
- var newErr = $interpolateMinErr ( 'interr' , "Can't interpolate: {0}\n{1}" , text ,
220
- err . toString ( ) ) ;
221
- $exceptionHandler ( newErr ) ;
222
- }
201
+ return extend ( function interpolationFn ( context ) {
202
+ var scopeId = context . $id || 'notAScope' ;
203
+ var lastValues = lastValuesCache . values [ scopeId ] ;
204
+ var lastResult = lastValuesCache . results [ scopeId ] ;
205
+ var i = 0 ;
206
+ var ii = expressions . length ;
207
+ var values = new Array ( ii ) ;
208
+ var val ;
209
+ var inputsChanged = lastResult === undefined ? true : false ;
210
+
211
+
212
+ // if we haven't seen this context before, initialize the cache and try to setup
213
+ // a cleanup routine that purges the cache when the scope goes away.
214
+ if ( ! lastValues ) {
215
+ lastValues = [ ] ;
216
+ inputsChanged = true ;
217
+ if ( context . $on ) {
218
+ context . $on ( '$destroy' , function ( ) {
219
+ lastValuesCache . values [ scopeId ] = null ;
220
+ lastValuesCache . results [ scopeId ] = null ;
221
+ } ) ;
222
+ }
223
+ }
224
+
225
+
226
+ try {
227
+ for ( ; i < ii ; i ++ ) {
228
+ val = stringify ( parseFns [ i ] ( context ) ) ;
229
+ if ( val !== lastValues [ i ] ) {
230
+ inputsChanged = true ;
231
+ }
232
+ values [ i ] = val ;
233
+ }
234
+
235
+ if ( inputsChanged ) {
236
+ lastValuesCache . values [ scopeId ] = values ;
237
+ lastValuesCache . results [ scopeId ] = lastResult = compute ( values ) ;
238
+ }
239
+ } catch ( err ) {
240
+ var newErr = $interpolateMinErr ( 'interr' , "Can't interpolate: {0}\n{1}" , text ,
241
+ err . toString ( ) ) ;
242
+ $exceptionHandler ( newErr ) ;
243
+ }
244
+
245
+ return lastResult ;
246
+ } , {
247
+ // all of these properties are undocumented for now
248
+ exp : text , //just for compatibility with regular watchers created via $watch
249
+ separators : separators ,
250
+ expressions : expressions
251
+ } ) ;
223
252
}
224
253
}
225
254
0 commit comments