Link to home
Start Free TrialLog in
Avatar of Crazy Horse
Crazy HorseFlag for South Africa

asked on

using ++ with jquery $.each()

I am trying to get the id value of the last image being shown which is the value in a checkbox. The id value looks like: "image_1, image_2 etc.

I just need the actual number so I have used the slice function to do so. If I upload 3 images for example, I then need to get the last id and increment by 1 for each new image added. So, if the last image is image_5 and I upload 3 new images, the new images should be image_6, image_7 and image_8. but the problem I am having is that all 3 images end up being image_6.

CODE:

$('#fileupload').fileupload({
    url: url,
    dataType: 'json',
    done: function (e, data) {
        var lastBox = $( 'input[name="pics[]"]' ).last().data("id");
        var lastId = parseInt(lastBox.slice(6));
        var total = lastId;
        $.each(data.result.files, function (index, file) {
            total++;
            console.log(total);
            $( "#gallery-body" ).prepend(`

                <div class="col-md-3 img-box">
                    <input type="checkbox" id="image_${total}" name="pics[]" value="${file.name}" data-id="image_${total}" />
                    <label for="image_${total}" style="background-image: url(uploads/${file.name})">
                        <i class="glyphicon glyphicon-ok"></i>
                    </label>
                </div>
                    `);

Open in new window


HTML OUTPUT:

<div class="col-md-3 img-box">
    <input type="checkbox" id="image_17" name="pics[]" value="IMG_5271.jpg" data-id="image_17">
    <label for="image_17" style="background-image: url(uploads/IMG_5271.jpg)">
        <i class="glyphicon glyphicon-ok"></i>
    </label>
</div>
<div class="col-md-3 img-box">
    <input type="checkbox" id="image_17" name="pics[]" value="dzone.jpg" data-id="image_17">
    <label for="image_17" style="background-image: url(uploads/dzone.jpg)">
        <i class="glyphicon glyphicon-ok"></i>
    </label>
</div>

Open in new window

Avatar of HainKurt
HainKurt
Flag of Canada image

what does your data look like?
Avatar of Crazy Horse

ASKER

@HainKurt, not sure I understand what you mean?
done: function (e, data) {

what is data look like here?
have a look at this demo

https://jsfiddle.net/HainKurt/5ofyu5g9/

I assumed data is something like this:

var data = {
  "result": {
    "files": {
      "file1": "1.jpg",
      "file2": "2.jpg",
      "file3": "3.jpg"
    }
  }
};

Open in new window

There is too much data to post here if I console.log() data because I am using blueimp upload script which generates a lot!

But my result is like I mentioned in the html output I posted. If the last image has an id of 16, and I upload 2 new images, they should have id's of 17 and 18. But they don't. They both have an id of 17 i.e., 16, 17, 17. Instead of 16, 17, 18.
If I use .last() and append(), instead of .last() and .prepend(), it works. The numbers then go in sequence because it shows me 17, 18. I think that is because it initially gets the last id of 16, adds 1 image (17), gets the id of 17 as that is the new last image  and so the next one is 18 after that. But even though this works, it isn't what I want. I don't want the new images to show right at the bottom of the list. They must become the first images.

So, I tried .first() and .prepend() but that then gives me 2, 3, 1, 2, 3 which also isn't correct.
Avatar of Chris Stanyon
I'm guessing that what's happening here is that each upload is handled separately and therefore the done() method get's called for each file in the list - over and over again until they're all done uploading.

This means that for each file that's uploaded, the lastId will be set to the same last item each time, which won't change if you're pre-pending rather than appending. It also won't work if you do subsequent uploads because the lastId won't represent the last image that was uploaded (that would be towards the top of your list, not the bottom).

You might want to do some testing to see if this is the case, and re-think you're logic to avoid the issue. Instead of using first() and last(), you might want to look at pulling all the IDs in, and then calling something like Math.Max(number, number, ...) to find out the max ID
As an other idea, you could set your lastId to a global variable rather than a local one so that it's not reset on very iteration of done() !!
How do I set it is a global variable?
Move it outside of your function:

var lastBox = $( 'input[name="pics[]"]' ).last().data("id");
var lastId = parseInt(lastBox.slice(6));
var total = lastId;

$('#fileupload').fileupload({
    url: url,
    dataType: 'json',
    done: function (e, data) {
        $.each(data.result.files, function (index, file) {
            total++;
            console.log(total);
            ...

Open in new window

Yeah, that's what I thought but then I get the following error:

Uncaught TypeError: Cannot read property 'slice' of undefined
SOLUTION
Avatar of leakim971
leakim971
Flag of Guadeloupe image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you, leakim971. I tried your code but the same thing happens. Instead of 16, 17, 18, I get 16, 17, 17.
Your error's indicating that lastBox is not being set correctly. Without seeing your full code, can't tell you why that's the case. Just make sure everything is wrapped in the doc.ready block as usual.
The very first bit of code is to get the existing images from the uploads directory:


$.get('t2637.php', function (data) {
	$('#gallery-body').html(data);
});

Open in new window


That is where the images are displayed and each image has a checkbox associated with it and an Id e.g.: image_1, image_2 etc.

So, I would have thought that I could have done this:

$.get('t2637.php', function (data) {
   $('#gallery-body').html(data);
   var lastBox = $( 'input[name="pics[]"]' ).last().data("id");
   var lastId = parseInt(lastBox.slice(6));
   var total = lastId;
});

Open in new window


But even that gives me the slice error.

The lastBox variable is just getting the id value of the last checkbox.
I understand what lastBox is. My point was that for some reason it's returning undefined, so it's not seeing the inputs on your page. The fact that you're loading the data dynamically means that you have to be careful in what order you call that function, otherwise the inputs won't exist when you need to select them.

For a variable to be global, it need to be outside of a function. The code you've just posted has just moved it into a different function!
But how can I put lastId outside of the function and make it global if I haven't even called the images yet? Surely that would result in undefined?
replace :
console.log(total);
by :
alert(total);

and please confirm total change value
could you share a link to your page
	var lastBox = $( 'input[name="pics[]"]' ).last().data("id");
		var lastId = parseInt(lastBox.slice(6));
		var total = lastId;
                    $(function () {
                       $.get('t2637.php', function (data) {
	               $('#gallery-body').html(data);
                    });

Open in new window


Trying to get lastBox before lastBox is even defined. That is what I understand but it's more than possible I am misunderstanding.
var lastId; // declare a global variable

function doSomething() {
   ...
   lastId = 123; // set the global variable
}

function doSomethingElse() {
   alert(lastId); // use the global variable
}

Open in new window

Please give me a moment to try this.
Is this what it is supposed to look like?

<script type="text/javascript">
	var lastId;
	$(function () {
	      $.get('t2637.php', function (data) {
              $('#gallery-body').html(data);
	});
$('#fileupload').fileupload({
        url: url,
        dataType: 'json',
        done: function (e, data) {
		var lastBox = $( 'input[name="pics[]"]' ).last().data("id");
		var lastId = parseInt(lastBox.slice(6));
		var total = lastId;

            $.each(data.result.files, function (index, file) {
			total++;
                       alert(total);
			var filename = file.name;
			var str = '<div class="col-md-3 img-box">';
			str += '<input type="checkbox" id="image_' + total +'" name="pics[]" value="' + filename + '" data-id="image_' + total +'" />';
			str += '<label for="image_' + total +'" style="background-image: url(uploads/' + filename + ')">';
			str += '<i class="glyphicon glyphicon-ok"></i>';
			str += '</label>';
			str += '</div>';
			$( "#gallery-body" ).prepend(str);

Open in new window

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ahah, that works! Was total causing the problem? Because not much has changed except total was removed and you used lastId instead?
And by the way, I removed the global variable,

var lastId

Open in new window


and it still works!
Be careful when you remove the var lastId. By keeping it in, you're explicitly declaring a global variable. By removing it, the global variable gets declared implicitly, so it still exists at the global level. This may lead to confusion down the line when you wonder where a variable was declared. It will also break if you try to run in strict mode - it's always good practice to declare your variables explicitly :)

Glad you got it working :)
Okay, so you are saying that even though it works without, I should declare var lastId;

?
Yeah - considered best-practice :) If you don't declare it, then it will get magically declared anyway, so you might as well be explicit!
Great, thanks so much for your help and patience. This problem was driving me crazy!
You're welcome :)