Constraint the effect of JQuery Code

JS script →

<script type="text/javascript">
$(document).ready(function() {
var max_fields      = 10; //maximum input boxes allowed
var wrapper   		= $(".html_js"); //Fields wrapper
var add_button      = $(".buttonjs"); //Add button ID

var x = 5; //initlal text box count
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).append('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value="">  <input type="text" name="" value="">'); //add input box
}
});
});
</script>

The code works absolutely fine, but the issue is that when add button is clicked it add susbjects to all the semester. How should we correct the code to get rid of this behavior. It should work on just the one semester.

Live Link

Consider what this targets.

1 Like

Yes, I understand that, but does that mean I have to use seperate class for every semester. That will increase so much code.

+

Later semesters will be increased through click button that will increase so much code. No alternative to improve the code w/o needing so many classes?

No.

So here’s your next jQuery lesson:
Event Based DOM navigation.

You’ve bound your click event to $(“.buttonjs”).
From the jquery documentation for on (click is a shorthand for on('click',...)):

So, challenge to you time:
Combine the above knowledge with this hint and see if you can solve your problem.

1 Like

I got the logic of Previous selector, but still could not visualize how to use this? can you please guide me?

Based on the paragraph of text, while inside your click event, what is $(this) pointing at?

It will point at that particular button(wrapper).

Current:

$(wrapper).append

You mean this:

$(this.wrapper).append.prev()

there are two version of this:

$(this) and $this

You’re on the right track.

$(this) points to the specific button that was pushed. We dont need wrapper at that point. We’re already in the DOM, pointing at that button. So what we want to do is put something in immediately before that button.
You’ve been using .append, but i’m actually going to suggest that’s the wrong way to go about it; at least, it’s creating elements inside the wrong container.
Push your button a few times, and look at the HTML you’ve created.

Doing it with the current method:
We’re pointing at the button with $(this). You’re trying to insert the new field into the previous sibling of the button. So, walk the pointer up one sibling .prev(), and then .append()
[And you’ll note if you simply read that sentence out, you’ll get the appropriate code… $(this).prev().append(...) ]

I’m going to suggest that instead of trying to append to that last child, you instead use the insertBefore method. Since you want to add an element directly before the selected button, the code phrase would be “We’re pointing at the button with $(this). We’re trying to insert an element before (.insertBefore) that button.”

2 Likes

You mean this →

Current:

$(this).prev().append('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value=""> <input type="text" name="" value="">'); //add input box

Later

$(this)('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value=""> <input type="text" name="" value="">').insertBefore(".buttonjs"); //add input box

actually that one goes a little backwards because of how they constructed insertBefore. Which… is confusing, but… I didnt write jQuery. :stuck_out_tongue:

$('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value=""><input type="text" name="" value="">').insertBefore(this);
1 Like

That means the wrapper is useless now:

var wrapper = $(".html_js"); //Fields wrapper
?

Well unless you have another use for it, or if your HTML structure changes.

1 Like

You were very helpful and harsh to throw challenge(Pushing me out of the comfort zone) to let me learn and grow. thank you so much for your time and intention to help someone evolve and grow.

2 Likes

Hi there @m_hutley,
what we did today is slightly flawed. It is incrementing a total of 10.

If we increment 4 in semester 1 than only 3 will be incremented in semester 2 or 3. However, what I wanted to set was that each semester can have a maximum of 10 subjects.

I will be requesting your help sir because here onwards I have no idea how to move forward.

Well, that’s not something I did. :stuck_out_tongue:

My recommendation here would be to build off of our previous lesson about DOM navigation. Instead of relying on a fixed variable.

Here are your hints for this:

3 Likes

I have read these two and it looks like the parent and find method are reciprocal to each other.
parent traverse the immediate parent unlike the parents, which traverse all the parent: parent, grand parent, great grand parent.

I tried this:

$('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value=""><input type="text" name="" value="">').insertBefore(this).parent()

It doesnt seems to be work may be syntax is not right.

They… are but they aren’t reciprocal. It’s all about tree traversal and scope.

In our previous example, we identified that $(this) is pointing at an element.

Consider what you want to do now, in English. Not even going to talk code yet.

“What I want to do is add an element to this group, but only if there aren’t already 10 of them in the group that I’ve clicked the button on.”

Well, we covered part of this before. We know how to add an element to the group. We had that answer in post 11. What about the rest of it?
So, we clearly need an if. I mean, we said the word if in our sentence, so clearly we need one. But an if needs a condition.
Our condition requires us to count things, because we know we shouldn’t do anything if there’s already 10 of these elements. But how do we know how many elements are in the group? In fact, how do we know which ‘group’ we’re talking about at all?
The group I’ve clicked the button on. Ah, so here’s our triggering element - the point at which we enter the DOM tree. We enter, pointing at the button that was clicked.

Now, I’ve given you one method of finding the answer to the green piece. There is another (probably simpler, but it’s good to learn about traversing anyway… think of it like maths classes in school. You learn the complex way, and then you learn the shortcuts :stuck_out_tongue:)

.parent goes ‘up’ one level of the DOM tree. So in the case of your code, .parent() shifts the pointer up one level, and points it at the ‘class’ <div>. Note that we can keep going up and up and up until we hit the document (the root of the tree) by invoking parent multiple times;
var mystery = $(this).parent().parent().parent();
(Pop quiz: What element is mystery pointing at, if $(this) is pointed at Semester 2’s button?)

.find(selector) is almost the reciprocal of that function, but it searches the children of the target element for matches to selector. This way you can identify how many <div>'s are inside of an element, without having to count the number of buttons too.
.children(selector) is almost the same as .find(selector), except it only searches the immediate children of the target, and find recursively digs into the children. In this particular example, it makes no difference which you use, because the children of your semester don’t themselves have children.

The line that adds a class was correct in post #11. Leave that alone, it goes inside our if. Write for me the if condition that satisfies the green text above.

1 Like

I think it is

<main>

syntax may be wrong, but logical understanding may be right:

if($(this).x)!=10) {
	$('<div class="htmljs"><label for=""><h3>Subject 1</h3></label><input type="text" name="" value=""><input type="text" name="" value="">').insertBefore(this);
}

Well you got the quiz right :wink:

Let’s try it this way. Forget everything about your current code.

I give you the following HTML:

<sample>
   <cheese type="Cheddar"></cheese>
   <cheese type="Brie"></cheese>
   <cheese type="Goudda"></cheese>
   <cheese type="Limberger"></cheese>
   <cheese type="Pepper Jack"></cheese>
   <board type="Cedar"></board>
</sample>

and you know the following:
1: jQuery is loaded.
2:In my javascript, I have defined a variable:

var x = $('board[type="Cedar"]');

Using only the 3 functions linked in post #16 (Hint: You should use all three, only once each), and only 1 line of code, define the number of cheeses in my HTML. Start with x.

2 Likes

hi there, thanks for the guidance and creating tutorial. before I try writing please tell me if i have undersood that in english correctly.

<board type="Cedar"></board>

Code should return just “1” right?