1

I'm using cropin jQuery plugin in my project and going to pull updates for it in future so I don't want to change it's code.

Inside the plugin it changes the value of <input> element using val() function but doesn't instantly trigger the change event which means that I cannot listen to event using code like this:

on("change", function(){
 //do something; 
})

*details can be found here: .val() doesn't trigger .change() in jquery

Question: is there any workaround for this? How can I listen to change event without modifying the plugin code if plugin:

  1. uses val() to modify the elements value

  2. doesn't trigger change event following the val() call?

Community
  • 1
  • 1
Mikhail Romanov
  • 1,542
  • 1
  • 13
  • 20
  • You can't, if the plugin changes the value programatically no event will be fired, and the only way to fix that is changing the plugin, adding a `trigger('change')` call. – adeneo Dec 13 '15 at 16:52
  • 1
    You can patch jquery, see this answer http://stackoverflow.com/a/23635867/822711 or this answer http://stackoverflow.com/a/27477455/822711 but you may as well patch the plugin instead. – Popnoodles Dec 13 '15 at 17:06
  • @Popnoodles In this case I will get an infinite loop if plugin author one day put `val()` inside the `change` event handler – Mikhail Romanov Dec 13 '15 at 17:15
  • What about using MutationObservers? https://developer.mozilla.org/it/docs/Web/API/MutationObserver it is plain javascript, not supported in all browsers as it is new. I can't see any other solution which does not involve the use of jQuery or modifying the plugin source code. (The other option is polling with setTimeout) – Warrior Dec 13 '15 at 17:56
  • 1
    @MichaelRomanov read the code, it won't loop – Popnoodles Dec 13 '15 at 18:12
  • @Popnoodles, Now I see: before firing the event it checks if the value was actually changed or not. Looks good for me, thanks a lot. Will use this solution. – Mikhail Romanov Dec 14 '15 at 02:30

3 Answers3

1

I don't know if it works because I have never done it. However, according to: redefining-a-jquery-function you could redefine jQuery's val function to trigger a change event.

In this way you won't have to touch the plugin and calling val() will fire an event every time it is called. Sample code is included in the link provided.

EDIT: Answers to similar questions state that it is bad practice as sometimes doing so leads to an unpredictable behavior of jQuery.

Community
  • 1
  • 1
Warrior
  • 563
  • 1
  • 6
  • 20
1

You could decorate the jquery val function.

edit: I couldn't resist making the suggested changes as it's such a good solution.

// jQuery plugin to decorate .val
(function( $ ){
  var __val = $.fn.val,
      // save the previous values to a hash table
      values = {};
  $.fn.val = function( newVal ){
    // create a unique key based on tag offset id & class
    var hashId = this.prop('nodeName').toLowerCase() + '[' + this.index() + ']' + '#' + this.attr('id') + '.' + this.attr('class').replace(' ', '.');
    console.log('hashId', hashId);
    if( newVal && ( !values[ hashId ] || ( values[ hashId ] !== newVal ) )) {
      values[ hashId ] = newVal; 
      var ret = __val.apply(this, arguments);
      this.trigger('change');
      return ret;
    }
    console.log('no change');
    return __val.apply(this, arguments);
  }
})( jQuery );

var $input = $('#input'),
    $changer = $('#changer');

$input.on('change', function(e){
  console.log('changed: ' + this.value );
});

$changer.click(function(){
  $input.val('something');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
<input id='input' class="some-input" type='text'>
<button id="changer">change</button>
synthet1c
  • 6,152
  • 2
  • 24
  • 39
  • This works but can be dangerous in case of plugin author will put the `val()` inside `change` event handler. – Mikhail Romanov Dec 13 '15 at 17:36
  • 1
    that's a valid point, but the only other way I could think to do it is modify the plugin or check that the content has changed at a timeout interval. it's a bit hacky though. – synthet1c Dec 13 '15 at 17:46
  • as @Popnoodles mentioned above there is same solution as yours with one difference: before firing the event it checks if the value was actually changed or not (stackoverflow.com/a/23635867/822711). Works for me :) – Mikhail Romanov Dec 14 '15 at 02:39
-1

See this http://jsfiddle.net/cqz2u8x8/1/ fiddle for different change events. You might want to try the on('input') event. This seems to trigger every time a real change in value has occured.

$("#testinput").on('input', function(e) {
    $("#valuetyped-input").html(e.target.value)
});
Paretozen
  • 7
  • 2
  • Updated your example so you would understand what I mean: http://jsfiddle.net/cqz2u8x8/5/. Type something into `#testinput2` and you will see that `#testinput` is updated but events are not triggered – Mikhail Romanov Dec 13 '15 at 17:26