JQuery and "this" confusion

	$(".button").click(function () {
		var id = $(this).attr("id");
		if (id == "next") {
			$("#prev").removeClass("disabled");
			if ( child >= length ) {
				$(this).addClass("disabled");
				$("#submit").removeClass("disabled");
			} else if ( child <= length ) {
				child++;
			}
		} else if(id == "prev") {

		}
	});

this is a shorthand, but I am confused here what is this pointing at?

Is it the clicked button element or the section?

This is the HTML →

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="svg_wrap"></div>
  <h1>Online Application</h1>
  <section>
    <p>Personal information</p>
    <input type="text" placeholder="Firstname" />
    <input type="text" placeholder="Surname" />
    <input type="text" placeholder="Birthdate" />
    <input type="text" placeholder="Insurance number" />
    <input type="text" placeholder="Family status" />
  </section>

  <section>
    <p>Address</p>
    <input type="text" placeholder="Street, nbr" />
    <input type="text" placeholder="City" />
    <input type="text" placeholder="Postcode" />
    <input type="text" placeholder="Country" />
  </section>

  <section>
    <p>Contact information</p>
    <input type="text" placeholder="Email address" />
    <input type="text" placeholder="Phone" />
    <input type="text" placeholder="Mobile" />
  </section>

  <section>
    <p>Application</p>
    <input type="text" placeholder="Preferred entrance date" />
    <input type="text" placeholder="Number of people" />
  </section>

  <section>
    <p>General condtitions</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </section>

  <div class="button" id="prev">&larr; Previous</div>
  <div class="button" id="next">Next &rarr;</div>
  <div class="button" id="submit">Agree and send application</div>


  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="custom.js"></script>
</body>
</html>

Full JS code so far →

$( document ).ready(function() {
	var child = 1;
	var length = $("section").length - 1;
	console.log(length);
	$("#prev").addClass("disabled");
	$("#submit").addClass("disabled");
	$("section").not("section:nth-of-type(1)").css('transform','translateX(100px)');
	$("section").not("section:nth-of-type(1)").hide();

	$(".button").click(function () {
		var id = $(this).attr("id");
		if (id == "next") {
			$("#prev").removeClass("disabled");
			if ( child >= length ) {
				$(this).addClass("disabled");
				$("#submit").removeClass("disabled");
			} else if ( child <= length ) {
				child++;
			}
		} else if(id == "prev") {
		}
	});
});

Its the button that you were clicking.

If you click next a few times then it gets added here.

<div class="button disabled" id="next">Next →</div>

2 Likes

Thanks, I think that this part of the code is slightly flawed:

Child will never be greater then length, which is one minus the total number of section container?

image

Or i am still missing the exact point?

That says greater than or equal to.

Open devtools and click next a few times and you will see the class get added to the html in real time :slight_smile:

1 Like

Or just… don’t use this at that particular point, and use the explicit definition:
Enable all buttons.
If you’re at the end of your dataset, disable the ‘next’ button; else, disable the submit button.
If you’re at the beginning of your dataset, disable the ‘previous’ button.

this is for abstraction; You don’t know WHICH button was pushed at the start of the code, so you check this's ID attribute to tell you.
There is no ambiguity when it comes to which button you want to disable.

2 Likes

I agree about not using the this keyword. It just leads to too much confusion.

Instead, get an event object from the event handler. It’s customary to use a parameter of evt for the event object.

    $(".button").click(function (evt) {

Anywhere inside of that click function you can use evt.target to gain a reference to the button that was clicked. It’s handy to assign that to a local variable.

    $(".button").click(function (evt) {
        var button = evt.target;

We can then replace uses of this, with that button variable instead, which helps to make it easier to understand what is going on.

    $(".button").click(function (evt) {
        var button = evt.target;
        var id = $(button).attr("id");
3 Likes

Noted sir. Currently, I am struggling with some logical flow - Mental wrestling with some concepts. Once I am out of it and developed a full comprehension I will implement this version in the finished product.

It all make sense today. Thank you so much.

  $(".button").click(function (evt) {
    var button = evt.target;
    var id = $(button).attr("id");
    if (id == "next") {
      $("#prev").removeClass("disabled");
      if (child >= length) {
        $(button).addClass("disabled");
        $('#submit').removeClass("disabled");
      }
      if (child <= length) {
        child++;
      }
    } else if (id == "prev") {
      $("#next").removeClass("disabled");
      $('#submit').addClass("disabled");
      if (child <= 2) {
        $(button).addClass("disabled");
      }
      if (child > 1) {
        child--;
      }
    }

For better understanding I have made it more semantic and thus changed child to sectionNum:

$( document ).ready(function() {

  var sectionNum = 1;
  var length = $("section").length - 1;
  console.log(length);
  $("#prev").addClass("disabled");
  $("#submit").addClass("disabled");
  $("section").not("section:nth-of-type(1)").hide();
  $("section").not("section:nth-of-type(1)").css('transform','translateX(100px)');
   
  $(".button").click(function (evt) {
    var button = evt.target;
    var id = $(button).attr("id");
    if (id == "next") {
      $("#prev").removeClass("disabled");
      if (sectionNum >= length) {
        $(button).addClass("disabled");
        $('#submit').removeClass("disabled");
      }
      if (sectionNum <= length) {
        sectionNum++;
      }
    } else if (id == "prev") {
      $("#next").removeClass("disabled");
      $('#submit').addClass("disabled");
      if (sectionNum <= 2) {
        $(button).addClass("disabled");
      }
      if (sectionNum > 1) {
        sectionNum--;
      }
    }

    var currentSection = $("section:nth-of-type(" + sectionNum + ")");
    currentSection.fadeIn();
    currentSection.css('transform','translateX(0)');
    currentSection.prevAll('section').css('transform','translateX(-100px)');
    currentSection.nextAll('section').css('transform','translateX(100px)');
    $('section').not(currentSection).hide();
  });

});
1 Like

Just for your consideration :slight_smile:

Taking Paul’s discussion in the other thread into account, you could also change those ‘vars’ for ‘const’ and ‘let’

Personally I like to use standardJS. It not only prettifies your code, but picks up on all the small errors — I appreciate it is opinionated, but can be very useful.

So for instance a few of the minor errors or problems that came up with your script

Missing space before function parentheses. (space-before-function-paren) [1, 19]
There should be no space after this paren. (space-in-parens) [3, 3]
Strings must use singlequote. (quotes) [6, 18]
Expected '===' and instead saw '=='. (eqeqeq) [16,12]
Unexpected var, use let or const instead. (no-var) [5, 3]
Block must not be padded by blank lines. (padded-blocks) [3, 32]

Thankfully standardjs can be configured in vscode settings with “standard.autoFixOnSave”: true,

So a save (ctrl-s) will fix most of the issues.

Also cleverly it will identify whether ‘const’ or ‘let’ is more suitable. e.g. if the variable is a changing value e.g. var count = 0; count++ it will change that to let count = 0

Anyway this is the output. It does remove semi-colons, which I prefer, you may not. These things can be configured

$(document).ready(function () {
  let sectionNum = 1
  const length = $('section').length - 1

  console.log(length)
  $('#prev').addClass('disabled')
  $('#submit').addClass('disabled')
  $('section').not('section:nth-of-type(1)').hide()
  $('section').not('section:nth-of-type(1)').css('transform', 'translateX(100px)')

  $('.button').click(function (evt) {
    const button = evt.target
    const id = $(button).attr('id')

    if (id === 'next') {
      $('#prev').removeClass('disabled')

      if (sectionNum >= length) {
        $(button).addClass('disabled')
        $('#submit').removeClass('disabled')
      }

      if (sectionNum <= length) {
        sectionNum++
      }
    } else if (id === 'prev') {
      $('#next').removeClass('disabled')
      $('#submit').addClass('disabled')

      if (sectionNum <= 2) {
        $(button).addClass('disabled')
      }

      if (sectionNum > 1) {
        sectionNum--
      }
    }

    const currentSection = $('section:nth-of-type(' + sectionNum + ')')

    currentSection.fadeIn()
    currentSection.css('transform', 'translateX(0)')
    currentSection.prevAll('section').css('transform', 'translateX(-100px)')
    currentSection.nextAll('section').css('transform', 'translateX(100px)')
    $('section').not(currentSection).hide()
  })
})
1 Like

I hope that there is sublime text version to this. May be this one →
https://packagecontrol.io/packages/StandardFormat

I could never wrap my head around $(this), so it’s always confusing to me as to what it refers to.

Because of that confusion it’s typically best to stay away from the this keyword, and use other techniques instead.

For example, when you are inside of a click event, $(this) refers to the element that was clicked.

$('.class-name').on('click', function () {
    $(this).hide();
}); 

There are more explicit ways to achieve that, by getting the clicked element from the event object instead.

$('.class-name').on('click', function (evt) {
    $(evt.target).hide();
}); 
3 Likes

I haven’t used sublime in a long time. Not as user friendly and missing the useful built in terminal.

Yes you are right with that package.

Note you will need nodejs installed

Due to no terminal, I had to open a cmd window and navigate to the folder I wanted to work in

eg:

cd webdev/sitepoint

Then install standardjs locally

npm install standard --save-dev

I also had to install sublimelinter and the sublimelinter-standard package

Result

And will fix on save

I don’t miss working with sublime. If you are not tied to it, vscode is well worth looking into.

1 Like