BarryBones41
BarryBones41

Reputation: 1481

jQuery Replace With only works once for an object reference

I'm having a strange issue with replaceWith (or more likely with object referencing).

I am trying to create a kind of table of rows that either have empty slots or full slots. As a demonstration I made this simple fiddle. http://jsfiddle.net/Ltxtvyn3/3/ In this fiddle 4 empty slots are initialized. Then one is filled. Then the same one should be emptied. But instead it is remaining filled. It is as if I can only use replaceWith once, or I am not understanding something about my object references.

HTML

<div class = "slot empty">Empty</div>
<div class = "slot full">Full</div>

<div class = "wrapper"></div>

CSS

.slot{
    width:50px;
    height:50px;
    display:none;
}
.empty{
    background-color:red;
}
.full{
    background-color:blue;
}

Javascript

var wrapper = $('.wrapper');
var empty = $('.slot.empty');
var full = $('.slot.full');

var slots = {};

for(var i = 0; i < 4; i++){
    slots[i] = empty.clone().show();
    wrapper.append(slots[i]);    
}

function fillSlot(id){
    slots[id].replaceWith(full.clone().show());
}

function emptySlot(id){
    slots[id].replaceWith(empty.clone().show());
}

fillSlot(1);
emptySlot(1);

I am hoping that the object var slots maintains a reference to the divs and I'm not sure if it is doing that or not.

Upvotes: 2

Views: 366

Answers (5)

Zakaria Acharki
Zakaria Acharki

Reputation: 67505

UPDATED

Your code work fine just if you change the selection method and you don't want slots list no more.

Replace :

function fillSlot(id){
    slots[id].replaceWith(full.clone().show());
}

function emptySlot(id){
    slots[id].replaceWith(empty.clone().show());
}

BY :

function fillSlot(id){
    wrapper.children().eq(id).replaceWith(full.clone().show());
}

function emptySlot(id){
    wrapper.children().eq(id).replaceWith(empty.clone().show());
}   

Selecting directly from wrapper what means selecting from fresh DOM. that will fix the problem, take a look at updated fiddle bellow.

Updated JSFiddle

Upvotes: 2

nril
nril

Reputation: 568

The problem is slots[i] isn't pointing to the div - so replaceWith won't pick the right item. Update the loop as follows (adding slots[i] = wrapper.find(':last-child') ):

for(var i = 0; i < 4; i++){
    slots[i] = empty.clone().show();
    wrapper.append(slots[i]);
    slots[i] = wrapper.find(':last-child')
}

Actually this may make the code a little easier to understand (replace loop with this instead)

for(var i = 0; i < 4; i++){
    wrapper.append(empty.clone().show());
    slots[i] = wrapper.find(':last-child')
}

Tested and works on FF..

Upvotes: 1

BarryBones41
BarryBones41

Reputation: 1481

Thanks for the answers. I know understand why the object doesn't keep a reference, and I really wanted that to be the case. I simply added a wrapper slot and then I will affect the contents of the wrapper. That way I always have a reference to the slot.

HTML

    <div class="slot-content empty">Empty</div>
<div class="slot-content full">Full</div>
<div class = "slot"></div>
<div id="wrapper"></div>

Javascript

var wrapper = $('#wrapper');
var slot = $('.slot');
var empty = $('.slot-content.empty');
var full = $('.slot-content.full');

var slots = {};

for(var i = 0; i < 4; i++){
    slots[i] = slot.clone().show();
    slots[i].html(empty.clone().show());
    wrapper.append(slots[i]);
}

function fillSlot(id){
    slots[id].html(full.clone().show());
    slots[id].find('.slot-content').html('hello');
}

function emptySlot(id){
    slots[id].html(empty.clone().show());
}

fillSlot(1);
emptySlot(1);
fillSlot(2);

Upvotes: 2

colonelsanders
colonelsanders

Reputation: 824

It's not keeping a reference to the DOM element. If you still want to use the array, then you can just repopulate the list every time you update one of its elements. Not terribly efficient, but I suppose it saves you from keeping state in the DOM.

function redraw() {
  $('.wrapper').empty();
  for(var i = 0; i < 4; i++){
    wrapper.append(slots[i]);    
  }
}

JSFiddle

Upvotes: 0

Dave
Dave

Reputation: 10924

No, it's not keeping a reference, but you can fix this pretty easily.

Here's some running code:

var wrapper = $('.wrapper');
var empty = $('.slot.empty');
var full = $('.slot.full');

for(var i = 0; i < 4; i++){
  wrapper.append(empty.clone().show());    
}

function fillSlot(id){
  $(".wrapper .slot").eq(id).replaceWith(full.clone().show());
}

function emptySlot(id){
  $(".wrapper .slot").eq(id).replaceWith(empty.clone().show());
}

fillSlot(1);

setTimeout(function() {
  emptySlot(1);
}, 2000);
.slot{
    width:50px;
    height:50px;
    display:none;
}
.empty{
    background-color:red;
}
.full{
    background-color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class = "slot empty">Empty</div>
<div class = "slot full">Full</div>
<div class = "wrapper"></div>

Upvotes: 2

Related Questions