BobbyP
BobbyP

Reputation: 2245

Javascript object referencing last object of kind instead of itself

I have a javascript object which i am instantiating for each instance of a dom object. My code looks something like this

let div = null;

$(function() {
    div = {
        init: function(container) {
            this.loadDom(container);
            this.loadEvents();
        },

        loadDom:function(container) {
            this.$container = $(container);
            this.$buttons = this.$container.find('.button');
            this.$textPanel = $('.text-panel')
        },

        loadEvents: function() {
            let that = this;

            // output the item's id. This works correctly
            that.$textPanel.append(that.$container.attr('id') + '<br>');

            this.$buttons.on('click', function() {

                // output the item's id. This always outputs the last item
                that.$textPanel.append(that.$container.attr('id') + '<br>');
            });
        }
    };

    let divs = $('.item');
    if(divs.length > 0) {
        divs.each(function(){
            div.init(this);
        })
    }
});

here is a fiddle

I expect there to be one object created for each div with a class of 'item', and all the functions within that object to apply to that one div. i.e. when you click the red div, the container's id should be shown in the panel below.

In the loadEvents function, I list the id of the current div. This is run immediately and correctly lists "modal-1" and "modal-2". But when I run the same command after a button click, the id of the last div is always displayed rather than the current div.

How can I make the button click work so the id of the correct div is shown?

Thanks

Upvotes: 2

Views: 40

Answers (1)

briosheje
briosheje

Reputation: 7446

I have reviewed the code by making div a function instead, so that the scope of each div will be unique and the events registered will belong to the div itself.

Other than that, the variable that was implicitly global, so I've added let before it so that it's correctly scoped.

It now works as intended

let div = null;

$(function() {
	div = function(){
  	return {
      init: function(container) {
        this.loadDom(container);
        this.loadEvents();
      },

      loadDom:function(container) {
        this.$container = $(container);
        console.log('con')
        this.$buttons = this.$container.find('.button');
        this.$textPanel = $('.text-panel')
      },

      loadEvents: function() {
        let that = this;

        // output the item's id. This works correctly
        that.$textPanel.append(that.$container.attr('id') + '<br>');

        this.$buttons.on('click', function() {

          // output the item's id. This always outputs the last item
          that.$textPanel.append(that.$container.attr('id') + '<br>');
        });
      }
    }
  }


	let divs = $('.item');
  if(divs.length > 0) {
  	divs.each(function(){
    	const _d = new div();
    	_d.init(this);
    })
  }
})
.container {
  display: grid;
  grid-gap: 30px;
  grid-template-columns: 1fr 1fr;
}

.item {
  border: 1px dotted green;
  height: 100px;
  width: 100%;
  display: inline-block;
  text-align: center;
}

.button {
  height: 50px;
  width: 50px;
  background: red;
  cursor: pointer
}

.text-panel {
  border: 1px dotted black;
  height: 200px;
  grid-column: 1/3;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="item" id="modal-1">
   <div class="button">click me</div>
   modal-1
  </div>
  <div class="item" id="modal-2">
   <div class="button">click me</div>
   modal-2
  </div>
  <div class="text-panel"></div>
</div>

Upvotes: 1

Related Questions