0

In my webapp i need to create a number of identical blocks (some text, rating, some buttons) with different content (that is, the text and rating is different, and the button id's are different). To that end, I am using jQuery templates.

At the same time, for the rating I use the "Raty" jQuery plugin. It shows the rating as a number of filled in and empty stars, and the value should be passed to it when the templates are populated with the data.

However, I cannot find a way to apply the plugin to the corresponding div at the moment of template processing.

Here is the code.

  1. the template
    <script id="clientTemplate" type="text/html">
        <span class="firstline" id="firstline_${id}">${firstline}
        <div class="star" id="s_${id}" style="cursor: pointer; width: 100px;"></div>
        {{if unescape( alert($data.importance)  )}}{{/if}}
        </span>
    </script>
    
    //the alert is there just to check that we can access the necessary data
  2. This is what we need to apply to the star div:
    $(".star").raty({
        half : true,
        score : 2.5,
        readOnly : false,
        click : function(score, evt) {
            if (readonly) {
                return false;
            }
            _id = $(this).attr("id");
            _id = id.replace("s", "");
            _id = _id.trim();
                $.ajax({
                    url : "importancereceive.html",
                    type : "POST",
                    data : {
                    id : _id,
                    importance : score
                },
                success : function(data) {
                    if (data != "1") {
                        alert("Failed to mark plan as completed");
                    }
                },
                error : function(jqXHR, textStatus, errorThrown) {
                    alert("error: " + textStatus);
                    alert("error: " + errorThronwn);
                }
            });
        }
    });
    
    // I need to replace the score value with the importance value from below
  3. And here is the data
    <script>
        var clientData = [ {
            id : 1,
            firstline : "My first line",
            importance : 2.0
        } ];
    </script>
    

How can i apply this plugin to each of the star divs while they are generated? I understand, that knowing the id of items I can iterate over the whole DOM and set the specific importance value to a specific star div, but that would mean iterating over the whole DOM a lot of times, that could pose problems for phones/tablets, esp. if the lists get big. Is there a way to apply the said thing to the div as it is being generated?

Ibolit
  • 9,218
  • 7
  • 52
  • 96
  • `iterating over the whole DOM a lot of times` is wrong. Template html isn't created in the DOM, and only one insertion is made in the DOM once all data is processed. Call plugin on the generated html before it is inserted – charlietfl Dec 30 '12 at 15:54
  • @charlietfl The problem is that i don't understand how. That is, i can apply the plugin to the generated HTML ($(".star").raty(...)), but I don't understand how to set the correct score value for each of these divs. By the way, $(this).data(..) or even $(this).attr(..) do not work there. – Ibolit Dec 30 '12 at 16:05

2 Answers2

1

Isn't it an idea to store the importance in a custom attribute of the div?

So your template would become something like:

<script id="clientTemplate" type="text/html">
    <span class="firstline" id="firstline_${id}">${firstline}
    <div class="star" id="s_${id}" style="cursor: pointer; width: 100px;" data-importance="${importance}"></div>
    {{if unescape( alert($data.importance)  )}}{{/if}}
    </span>
</script>

(I suppose it's something like this, I don't know your templating language)

See also Is it OK to add your own attributes to HTML elements? for more information on creating your own attributes.

And then you can get your importance using $(this).attr("data-importance").

EDIT: And then you can get your importance using $(this).data("importance"). (See source)

Community
  • 1
  • 1
bartlaarhoven
  • 825
  • 2
  • 8
  • 21
  • Yes, but the value set as "score" in the "raty" plugin is then represented as filled-in stars (say, if you set it to 2.4 you will have 2.5 stars filled in, and 2.5 stars just outlined, that is the middle one will be half-full) – Ibolit Dec 30 '12 at 15:27
  • Anyway, this way I will need to iterate over the DOM a second time, and the score setting logic will be separated from the template, but I want it to be there. Thank you for the reply, though :) – Ibolit Dec 30 '12 at 15:29
  • I tried this solution, but $(this).data("importance") returns "undefined". Turns out, $(this)[0] refers to the window. So does "this". – Ibolit Dec 30 '12 at 16:08
  • @Ibolit Where do you put `$(this)..`? Because if it's inside the `click` function, then it makes some sense.. (as then "this" will be the item where the click-event is triggered on) – bartlaarhoven Dec 30 '12 at 16:16
1

As with many plugins that rely on specific data for each instance you will have to loop over the elements to apply correct data to each instance.

As previously suggested store the scores in a data- attribute using template

$('.star').each(function(){
     var score=$(this).data('score')
     $(this).raty({
           half : true,
           score : score,
          /* other options*/
     });  
});

Your template engine should give you access to the html it generates before it is inserted.

You could call the plugin on the html it generates and you could loop over that html prior to DOM insertion also.

Some template engines are a little more flexible in how you can handle this. It depends on the template system used

charlietfl
  • 170,828
  • 13
  • 121
  • 150