Question

I've created a function to spice up my html forms that will check if all fields are valid on submit, and if not they flashed red to warn users. It all works great until the it tries to return the color back to normal.

if (response.length > 0) {
  for (var i = 0; i < response.length; i++) {
    if (response[i].getAttribute('field') != '') {
      var errField = $(response[i].getAttribute('field')+'Err');

      if (errField) {
        errField.set('html', response[i].getAttribute('msg'));
        var color = errField.getStyle('color');
        window['cfx'+i] = new Fx.Morph(errField, {
          duration: 400,
          transition: Fx.Transitions.Quad.easeInOut
        });

        window['cfx'+i].start({'color': '#000000'}).chain(function() {
          window['cfx'+i].start({'color': color});
        });
      }
    }
  }
}

I've debugged to the point where I can tell that it crashed when it gets inside the chained function, because it loses the variable at that point. I've looked around and I can't figure out how to get i into the chain function to work.

Was it helpful?

Solution

erm. basically, the iterator will run and the value of i passed to the chained function will be the index of the last item in the iteration, always.

several things you can do - a local closure near the calls is one or rewriting the whole loop to use Array.prototype.each like so:

response.each(function(el, i){
    if (el.getAttribute('field') != ''){
        var errField = $(el.getAttribute('field') + 'Err');

        if (errField){
            errField.set('html', el.getAttribute('msg'));
            var color = errField.getStyle('color');
            window['cfx' + i] = new Fx.Morph(errField, {
                duration: 400,
                transition: Fx.Transitions.Quad.easeInOut
            });

            window['cfx' + i].start({'color': '#000000'}).chain(function(){
                window['cfx' + i].start({'color': color});
            });
        }
    }
});

the value of i above will be fixed to the iterator within the function scope for each iteration, hence producing the desired effect.

alternatively these will work:

// permanent reference
var cfx = window['cfx' + i];
cfx.start({'color': '#000000'}).chain(function(){
    cfx.start({'color': color});
});

// binding the function via the outer scope to the element
window['cfx' + i].start({'color': '#000000'}).chain(function(){
    this.start({'color': color});
}.bind(window['cfx' + i]));

// encapsulating the i into a local closure
(function(i){
    // i is immutable here
    window['cfx' + i].start({'color': '#000000'}).chain(function(){
        window['cfx' + i].start({'color': color});
    });
}(i));

and finally, scope of chained functions is the Fx instance, which keeps a reference to the element being chained in this.element so this will always point to the element and this to the instance, hence you can just do:

window['cfx' + i].start({'color': '#000000'}).chain(function(){
    this.start({'color': color});
});

that's about it. have fun

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top