THIS reference is failing - javascript

I have this piece of code:
Drupal.behaviors.articleQuiz = (function(){
var _attach = function(context){
$('.question-container', context)
// .once()
.each(function(i, section){
new ArticleQuiz($(section));
});
};
return {
attach: _attach
};
})();
function ArticleQuiz($el){
this.$el = $el;
this.answer = this.$el.data('answer');
console.log('this.answer', this.answer);
this.quizLogic();
return this;
}
ArticleQuiz.prototype.quizLogic = function(){
var THIS = this;
$('.quiz-cols a').click(function(e) {
e.preventDefault();
// exit if choice already made: users can't change their pick
if ($(this).parents('.quiz-cols').parent().find('.white-font').length) {
return;
}
// set class according to data-answer:
$(this).addClass('background-' + (THIS.answer === true ? 'green' : 'red')).addClass('white-font');
console.log('answer', THIS.answer)
});
return THIS;
};
Drupal.behaviors.articleQuiz.attach($body);
In the function ArticleQuiz() you may see a console.log('this.answer', this.answer); which prints this and it's totally correct:
And then almost at the you may see this other console.log('answer', THIS.answer) which is within the click function and prints only true. Which means that is ignoring the other 2 falses that you might see in the picture I put above.
This is the html:
<div data-answer="true" class="question-container">
<div>
<h2>1. First question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
<div data-answer="false" class="question-container">
<div>
<h2>2. Second question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
<div data-answer="false" class="question-container">
<div>
<h2>3. Third question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
And just for you to know, the this.$el = $el; is pointing to div.question-container
As you see in that html there are 3 divs with class and data attribute data-answer="true" class="question-container", one of them is with data-answer=true and the other 2 are with data-answer=false.
So my question. Why in the first console.log I can see the 3 data-answer attributes coming up as they are: 1 true and 2 false. And in the click function it doesn't matter the container I click on, it only returns 3 true and ignores the false?
EDIT
The reference is working properly out of the click function.

You're creating a click handler for all the questions every time this.quizLogic() is called, instead of only for the current question. You can fix that by adding context to the selector before attaching the handler:
$('.quiz-cols a', this.$el).click(function(e) {
...

Related

Counting divs dynamically in combination with filters

I'm setting up a website with div filters and want to count div's dynamically depending on filter sets.
This code works fine but do not react dynamically on filter changes...
$('.detail').each(function(i) {
var n = $(this).children('.box').length;
$(".countDiv"+i).text("There are " + n + " divs inside parent box detail.");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content-body" class="clearfix">
<!-- detail div no 1 = 3 items inside -->
<span class="countDiv0"></span>
<div class="detail">
<div class="box">
Div item 1
</div>
<div class="box">
Div item 2
</div>
<div class="box">
Div item 3
</div>
</div>
<br /><br />
<!-- detail div no 1 = 4 items inside -->
<span class="countDiv1"></span>
<div class="detail">
<div class="box">
Div item 1
</div>
<div class="box">
Div item 2
</div>
<div class="box">
Div item 3
</div>
<div class="box">
Div item 4
</div>
</div>
</div>
Can anybody help?
well, too answer properly we would need to see the code that is performing the filter action. anyway, what you need to do is to encapsulate your code in a function and call that function whenever you are done filtering. example:
function countDivs() {
//your code here for counting the divs
}
function filterAction() {
//your code here that filters and creates the divs dynamically
countDivs()
}
$(document).ready(function(){
$("#btnCreate").click(function(){
$('.detail').append("<div class='box'>Div item n</div>");
});
});
$("body").on('DOMSubtreeModified', ".detail", function() {
$('.detail').each(function(i) {
var n = $(this).children('.box').length;
$(".countDiv"+i).text("There are " + n + " divs inside parent box detail.");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content-body" class="clearfix">
<!-- detail div no 1 = 3 items inside -->
<span class="countDiv0"></span>
<div class="detail">
<div class="box">
Div item 1
</div>
<div class="box">
Div item 2
</div>
<div class="box">
Div item 3
</div>
</div>
<br /><br />
<!-- detail div no 1 = 4 items inside -->
<span class="countDiv1"></span>
<div class="detail">
<div class="box">
Div item 1
</div>
<div class="box">
Div item 2
</div>
<div class="box">
Div item 3
</div>
<div class="box">
Div item 4
</div>
</div>
</div>
<div>
<button type="button" id="btnCreate">Create a new div inside detail div</button>
</div>
I can't understand what you mean by filter changes. What i understood was any changes made to the document DOM. If so then you need to bind the DivCount event like #folo(above) said to an event such as this..
$("body").on('DOMSubtreeModified', "mydiv", function() {
//countDiv();
});
Refer to this link
I have update my answer. please check
Please do the numbering as i have used n.
you can use mutation observer to listen on changes of children under your detail. more info about mutation can be found here https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver.
for your case, you can add that in the code inside each
1) add observer that takes care of dom changes
function createObserver(targetNode, cb) {
const config = { childList: true };
// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
for (var mutation of mutationsList) {
if (mutation.type == 'childList') {
cb();
}
}
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
}
2) hook that into your counting logic
$('.detail').each(function(i) {
const targetNode = this;
const countingDiv = $('.countDiv' + i);
const cb = () =>
countingDiv.text(
`There are ${
$(targetNode).children('.box').length
} divs inside parent box detail.`
);
cb();
createObserver(targetNode, cb);
});
you can see it in action here http://jsfiddle.net/sq5cd3rh/4/

jQuery ID Return is undefined although HTML ID is defined

I'm trying to retrieve the ID of one element, store it as a variable and then use that ID value to interact with other elements in that section with the same ID.
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">
</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore()">
</div>
</div>
And then the JS/jQuery
function readMore() {
var subID = event.target.id;
var newTarget = document.getElementById(subID).getElementsByClassName("articlePara");
alert(newTarget.id);
}
At this point I'm only trying to display the ID of the selected element but it is returning undefined and in most cases people seem to notice that jQuery is getting confused because of the differences between DOM variables and jQuery ones.
jsfiddle: https://jsfiddle.net/dr0f2nu3/
To be completely clear, I want to be able to click on one element, retrieve the ID and then select an element in the family of that clicked element using that ID value.
just remove the getElementsByClassName("articlePara"); in end of the newTarget .already you are call the element with id alert the element of the id is same with target.id
function readMore() {
var subID = event.target.id;
var newTarget = $('[id='+subID+'][class="articlePara"]')
console.log(newTarget.attr('id'));
console.log(newTarget.length);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mainContent">
<div class="articleContent">
<h1>header</h1>
<p class="articlePara" id="one"></p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">click
</div>
</div>
As you have read before, you should keep your id's unique, and you should avoid using onclick in html, but you could do it like this.
With querySelector you get the element and then with parentElement you can retrieve the parent of that element.
function readMore(el) {
var articleFooterId = el.id;
var articlePara = document.querySelector(".articleContent #"+articleFooterId);
var articleContent = articlePara.parentElement;
console.log('articleFooter', articleFooterId);
console.log('articlePara', articlePara);
console.log('articleContent', articleContent);
}
In your html you can return the 'this' object back to the function by doing readMore(this).
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore(this)">footertext</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore(this)">footertext</div>
</div>
jsfiddle
if you're using Jquery:
$(function () {
$('div.articleFooter').click(function () {
var para = $(this).prev().find('p.articlePara').text();
alert('T:' + para);
});
})
$('.articleFooter').click(function() {
var b=subId; //can be any
var a="p[id="+b+"]"+"[class='articlePara']";
$(a).something;
});
You have forgotten to pass in event as parameter in your onclick= call in html.
In your javascript, you need to include event in the parenthesis as well.
window.readMore = function(event) {...}
if you write document.getElementById(subID).getElementsByClassName("articlePara"); That's saying you want to get your clicked element's CHILD elements that have class equal to articlePara . There is none. So you get undefined.
If you want to find all element with a ID one and a class articlePara, it can be done easily with jQuery:
newtarget = $("#one.articlePara");
You can insert a line: debugger; in your onclick handler function to trigger the browser's debugging tool and inspect the values of variables. Then you will know whether you are getting what you want.

I need help passing a variable from a link into a function using defining a global variable in Jquery

Forgive me for my wording but this is the first time that I've written anything like this
I'm passing a freeMarker variable into a JQuery function on click of a link
<a onclick="showDisclaimer('${item.uid}')">Read the blog</a>
The variable passes fine but what I would like to do is show a hidden modal when the link is clicked. The name of the hidden modal is
<div class="disclaimer ${item.uid}" style="display:none;">
The code does not seem to be working. For one, I would like to define a global variable so that both functions have access to. As you can see I'm defining var x = uid; twice.
Also in my code $('body').append($('div.disclaimer x').remove()); does not work and I figure that it's because I haven't passed the variable yet or created a global variable. I just don't know how to do it.
My code is below. Any help is appreciated. Thanks
<#ftl ns_prefixes={"content":"http://purl.org/rss/1.0/modules/content/","dc":"http://purl.org/dc/elements/1.1/"}>
<script>
// Forces the disclaimer component to load on the body
$('body').append($('div.disclaimer x').remove());
function showDisclaimer (uid) {
var x = uid;
$('div.disclaimer x').show();
}
function closeDisclaimer(uid) {
var x = uid;
// Clear the form and close the modal
$('div.disclaimer x').hide();
}
</script>
<section style="background-color: #ededed">
<section class="head-transit">
<div class="container">
<div class="row-fluid">
<#list kiblogs.rss.channel.item as item>
<div class="span4">
<div class="panel">
<img src="${item.thumbnail.##nested_markup}" class="title-image">
<div class="top-content">
<h3>${item.title}</h3>
<div class="datetime">${item.pubDate}</div>
<div class="analyst"></div>
<p class="test">${item.description}</p>
</div>
<div class="disclaimer ${item.uid}" style="display:none;">
<div class="content">
<div class="close">x</div>
<h3>${item.title}</h3>
<div class="datetime">${item.pubDate}</div>
<p class="test">${item.description}</p>
<p class="${item.uid}">Hey now</p>
<div class="divider"></div>
</div>
</div>
<div class="bottom-content">
<div class="bottom-blue-buttn"><a onclick="showDisclaimer('${item.uid}')">Read the blog</a></div>
</div>
</div>
</div>
<div class="disclaimer ${item.uid}" style="display:none;">
<div class="content">
<div class="close">x</div>
<h3 class="title2"></h3>
<div class="divider"></div>
<p class="content2"></p>
</div>
</div>
<hr>
</#list>
</div>
</div>
</section>
</section>
I got the code to work but now I am getting a Console error that uid is not defined in var outerVar = uid; but uid is defined within my first and second function.
In my first line of code
var outerVar = uid;
$('body').append($('div.disclaimer' + outerVar).remove());
function showDisclaimer (uid) {
var x = uid;
$('div.disclaimer' + x).show();
}
function closeDisclaimer(uid) {
var x = uid;
// Clear the form and close the modal
$('div.disclaimer' + x).hide();
}
</script>
The css selector is wrong. You need to concatenate the x variable.
function showDisclaimer (uid) {
var x = uid;
$('div.disclaimer' + x).show();
}
function closeDisclaimer(uid) {
var x = uid;
// Clear the form and close the modal
$('div.disclaimer' + x).hide();
}
Example to reuse variables:
var outside = 'Fooo!';
function foo () {
console.log(outSide); //output 'Fooo!'
}
function bar() {
var inside = 'Hello';
console.log(inside); //output 'Hello'
}
console.log(inside); //output undefined
For more info on:
What is the scope of variables in JavaScript?

Why is not this onClick work?

I have the following reactJS/JSX code :
var LikeCon = React.createClass({
handleClick: function(like) {
return;
},
render(){
return this.renderLikeButton(this.props.like, this.props.likeCount)
},
renderLikeButton(like, likeCount){
return (
content = <div className={like==true ? "likeButConAct" : "likeButCon"}>
<div className="likeB" onClick={this.handleClick(!like)} > </div>
{ likeCount > 0 ? <div className="likeCount">{likeCount}</div>: null}
</div>
);
}
});
The problem is that handleClick will never be triggered even when I click the likeB div? Why?
Edit :
This is the code that uses the LikeCon component :
var TopicComments = React.createClass({
render: function() {
var comment = this.props.data.map(function(com, i) {
return (
<article>
<div className="comment">
<div className="tUImgLnk">
<a title={com.UserName} target="_blank" href={com.UserInfoUrl}>
<img className="tUImg" src={com.UserPicSrc} />
</a>
</div>
{com.UserName}
<div className="content">
{com.Message}
</div>
<div className="status">
<div className="dateCreated dimText">
{com.DateCreated}
</div>
<LikeCon like={com.Like} likeCount={com.LikeCount} />
<article></article>
</div>
</div>
</article>);
}.bind(this));
return(
<div className="comments">
{comment}
</div>
);
}
});
I suspect the problem is that the LikeCon is generating a markup for the TopicComment so the handleClick is not really there when triggered from the TopicComment. Is there a simple way to fix this?
You should be passing handle click event like so:
<div className="likeB" onClick={this.handleClick.bind(this,!like)} > </div>
With your current version you are passing result of executing this.handleClick(!like) to onClick handler which is undefined.
With above version you are passing a function which takes !like as its first parameter when executed.
Update:
Also since your div only contains a single space character, it is difficult to find the space character and click on it. If you add a text and click on that text, you will see the handle function is being executed:
working fiddle : http://jsfiddle.net/an8wvLqh/

Using jQuery to save the name of each div that has a specific class to a variable

I need to loop through a list of divs. If a div in that list has the class name of "active", than I need to save the contents of the <p></p> tag of the specific div to a variable. I then need to place the contents of that variable in a the value of a hidden input element on a form. For example, here is some example HTML:
<div class="names">
<div class="one active">
<p>A</p>
</div>
<div class="two active">
<p>B</p>
</div>
<div class="three">
<p>C</p>
</div>
<div class="four active">
<p>D</p>
</div>
<div class="five">
<p>E</p>
</div>
<div class="six active">
<p>F</p>
</div>
</div>
<form action="form.php" method="POST">
<input type="hidden" name="list" id="list" value="">
</form>
Since four of the divs contain the "active" class, I need to save the content that is in each paragraph tag to a variable to be inserted into the value of the hidden field. In this example, the value of the field would be A, B, D, F.
I thought about doing something like this:
var userSelection = function() {
$('.names div').each(function () {
if($(this).hasClass('active')) {
return $(this).text();
}
});
};
$('#list').val(userSelection);
First off, that code doesn't work and I am also not even sure if that's the best way to go about solving my problem. Second, if anyone has a better idea of how to accomplish what I need, I would love to hear it.
I would use map() to get an array of the text:
var textArr = $('.names div.active').map(function() {
return $(this).text();
}).get();
From there, you could use join() to get a string you could write to the DOM:
var textString = textArr.join(', ');
Full, compressed code:
var userSelection = function() {
return $('.names div.active').map(function() {
return $(this).text();
}).get().join(', ');
};
$('#list').val(userSelection());
Alternative to Jason P's answer is to modify what you've got to return an array of the results, as you're calling a function into a variable that has multiple results:
var userSelection = function() {
var output = [];
$('.names div').each(function () {
if($(this).hasClass('active')) {
output.push( $(this).text().trim() );
}
});
return output;
};
See JSFiddle.
Working fiddle: http://jsbin.com/uQEJIkU/3/edit
$(document).ready(function() {
values = []
$("div.active > p").each( function() {
values.push($(this).text())
})
})

Categories