20
var max = this.collection.max(function(player) {
    return player.get('points');
});

I spent a few hours playing with backbone.js trying to figure out how to check if my max model changes, it was nearly impossible, so I decided to set the models cid as a data-attribute now it seems impossible to check if the data-attribute changes?

I set the attribute like so,

$(this.$el).attr('data-id', max.cid)

When my app re-renders the data-attribute may or may not get a new value. I am really not sure how to check if it changes, I have seen a lot of various dirty hacks and setInterval functionality but nothing that seemed very clean, so I am hoping someone knows a nice clean way to do this?

Basically I just want control over the element if it renders new data from another model (meaning if another model takes the max value), I need to check the id to confirm that the model is a new version, and run an animation or render it showing that it is a new model.

Michael Joseph Aubry
  • 12,282
  • 16
  • 70
  • 135
  • Have you tried `console.log(DATA-ATTRIBUTE HERE);`? – Moduo Dec 24 '13 at 13:16
  • I `console.log($(this.$el).data('id'));` and got the right data-id, I am not sure I understand how that helps? – Michael Joseph Aubry Dec 24 '13 at 13:19
  • @MichaelJosephAubry I would store the data attribute and when you do a render check whether it is changed or not. This is simple right? – Praveen Dec 24 '13 at 13:22
  • Sounds simple but lets say I store the original data-attribute, then it changes to a new one, then it changes a third time? Thats why I need something that detects it without storing it? Am I making sense – Michael Joseph Aubry Dec 24 '13 at 13:26
  • @MichaelJosephAubry You're right, what is meant there is to create a method like generic so that you can use it whenever it changed. – Praveen Dec 24 '13 at 13:39
  • Your question could be : Is it possible to `bind` `data-*` attr change – Yabada Dec 24 '13 at 13:43
  • 1
    The attributes data-* NEVER change, data is stored in an object $.cache which is populated on page load and manipulated thereafter. This question has been asked previously http://stackoverflow.com/questions/11057748/how-to-monitor-when-the-body-data-attribute-changes-in-jquery – Popnoodles Dec 24 '13 at 13:47
  • Okay so it looks like I need to `setInterval()` to check what that value is, any idea what to set the timer to? like `setInterval(function() { var cid = $(this.$el).data('id')},300)` then it should get the new attribute, right? Let me try it. – Michael Joseph Aubry Dec 24 '13 at 13:53
  • Okay I got it up and working, but it kind of bugs me it keeps adding up in the console, is this not a problem? – Michael Joseph Aubry Dec 24 '13 at 14:00
  • You can't directly bind to attribute changes. Instead of polling for changes, I'd fire an event or similar, at the point of rendering, which you can then capture and react upon elsewhere. – Svend Dec 24 '13 at 14:02
  • I am still not sure about the best way to query if it is new? – Michael Joseph Aubry Dec 24 '13 at 14:02
  • @MichaelJosephAubry is it only your code that's updating the data? – Popnoodles Dec 24 '13 at 14:04
  • @Svend could you provide an example, I sort of get what you're saying but without some visual I can't quite get it. No one has provided an answer im sure if its decent you will win. – Michael Joseph Aubry Dec 24 '13 at 14:04
  • @popnoodles yeah, the data updates when there is a new max object. I have an array or collection of models, I return the model with the most points, when that model's id changed (a new model is the max), the data-attribute changes and I want to query if that change happens so I have more control over transitions. – Michael Joseph Aubry Dec 24 '13 at 14:04
  • @MichaelJosephAubry then the answer is simple. – Popnoodles Dec 24 '13 at 14:08

1 Answers1

24

First of all the data- attribute - while you can access the data attribute using .attr or .prop, data is stored in an object $.cache on page load and manipulated thereafter. The attributes data-* are NEVER updated.

To set data

$el.data('id', max.cid);

To get data

var something = $el.data('id');

Unfortunately there is no way to listen for a change in data without using setInterval as previously explored in this similar question.

That said, if it's only YOUR code that's updating the data, a logical solution is this:

Set up an event

$el.on('datachange', function(){
    // procedure here
});

Then either trigger it when you update the data

$el.data('id', max.cid).trigger('datachange');

or write your own data function that uses .data() and triggers the event

$.fn.mydata=function(key, variable){
    $(this).data(key, variable).trigger('datachange');
}

$el.mydata('id', max.cid);

Example: http://jsfiddle.net/Qn9H6/

$("#test").on('datachange', function(e, key){
    $('#feedback').hide().text('data "' + key + '" was changed to ' + $(this).data(key)).fadeIn(1000);
});

$.fn.mydata=function(key, variable){
    if ($(this).data(key)!=variable){ // check if it's changed
        $(this).data(key, variable).trigger('datachange', key);
    }else{
        console.log('data wasn\'t changed');
    }
}

$('button').click(function() {
    $("#test").mydata('id', $(this).text());
})

$("#test").mydata('id', 456);
Community
  • 1
  • 1
Popnoodles
  • 28,090
  • 2
  • 45
  • 53
  • That is not the question, you can even access the data-attribute using .attr – Praveen Dec 24 '13 at 13:39
  • Accessing the data-attribute using .attr WILL give you problems, the attribute is never updated. So the question is about a listener... – Popnoodles Dec 24 '13 at 13:40
  • 1
    *"Unfortunately there is no way to listen for a change in data without using setInterval"* what about [DOM Mutation events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events?redirectlocale=en-US&redirectslug=Web%2FGuide%2FAPI%2FDOM%2FEvents%2FMutation_events)? – Givi Dec 24 '13 at 14:17
  • @Givi There is no dom mutation on the event when data is changed, I already tried that. Updating data updates the object $.cache, not the element. You could use a hidden textarea as the data storage and dom mutation would be picked up there, but that's not ideal either. – Popnoodles Dec 24 '13 at 14:18
  • Looks good to me so far, added some events to change the data-attribute in the fiddle and it listens for the change. – Michael Joseph Aubry Dec 24 '13 at 14:19
  • How do I write a conditional with this? it keeps firing data attribute has changed, even though it's the same attribute. Im not sure how to write if `c80` becomes `c81` then do this? – Michael Joseph Aubry Dec 24 '13 at 14:30
  • 1
    Before updating the data (and triggering the event), check if what's sent is different to that which is it set to. I shouldn't need to write that out in code for you. – Popnoodles Dec 24 '13 at 14:33
  • 1
    I did anyway http://jsfiddle.net/Qn9H6/3/ – Popnoodles Dec 24 '13 at 14:37
  • Okay thanks checked it out and Im pretty sure since it's working there it will work. Definitely 1+ for the effort , understanding and working fiddles, will mark green as soon as I get it working :) – Michael Joseph Aubry Dec 24 '13 at 14:39
  • Look at [jsFiddle](http://jsfiddle.net/GKDev/9a7x3/) and documentation of [MutationObserver](https://developer.mozilla.org/en/docs/Web/API/MutationObserver) – Givi Dec 24 '13 at 14:50
  • Thanks @popnoodles I got it now, to Givi thanks for the resource, I am not sure how to trigger if the attribute changes with that though? – Michael Joseph Aubry Dec 24 '13 at 14:54
  • Givi's idea is excellent but if you were to use mutations I would strongly advise against refactoring how the data attribute is used and define something else, e.g. `mydata-id="123"`. Modifying how the data attribute is used may cause errors in the future when you revisit code, or for other devs who don't expect that odd behaviour, but using your own attribute would be a reasonable workaround. – Popnoodles Dec 24 '13 at 15:18
  • Is it possible to override jquery data function (`$.fn.data = function ()`) and trigger the event? – Sam Jul 02 '20 at 13:41
  • If you're looking for a non-JQuery alternative to this general idea (creating your own event upon data-attribute updates), check out [MDN's documentation](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#the_old-fashioned_way) on the `document.createElement()` API. I needed this alternative for legacy browser support. – Madhav Malhotra Feb 01 '23 at 14:13