I'm trying to learn how the object literals pattern works in Javascript.
In one of my projects i'm stuck on a part where I use some jQuery functions.
For the sake of the problem I build a little example.
I hope someone can provide me with some awesome hints.
Javascript: creating an object literal, and calling the init() method.
HTML: Some parts with a remove button. When clicked, I want to display an alert with the associated id extracted as data-attribute from the DOM. But there is the part it is failing, javascript does not know what .data means in that specific function.
Thanks... !
var test = {
init: function() {
this.dom();
this.events();
},
dom: function() {
this.$contentbox = $('.box');
this.$buttons = this.$contentbox.find('a');
},
events: function() {
this.$buttons.on('click', this.removeDiv);
},
removeDiv: function(event) {
event.preventDefault();
var div = this.closest('.removeMe'); // This works perfectly
var divID = div.data('id'); // Crashing -> Uncaught TypeError: div.data is not a function
alert('Product ' + divID + ' is to be deleted...');
}
}
test.init();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
<div class="content">
Hi there! Click X to delete item :)
</div>
<div data-id="6" class="removeMe">
Product 6 (X)
</div>
<div data-id="7" class="removeMe">
Product 7 (X)
</div>
<div data-id="8" class="removeMe">
Product 8 (X)
</div>
</div>
div is a vanilla HTMLDivElment not a jQuery object so has no .data() method, instead:
var divID = $(div).data('id')
Related
I need to change the location.href of some URLs on my site. These are product cards and they do not contain "a" (which would make this a lot easier).
Here is the HTML:
<div class="product-card " onclick="location.href='https://www.google.com'">
I mean it is pretty simple, but I just cannot get it to work. Did not find any results from Google without this type of results, all of which contain the "a":
$("a[href='http://www.google.com/']").attr('href', 'http://www.live.com/')
Any ideas on how to get this to work with jQuery (or simple JS)?
I cannot change the code itself unfortunaltely, I can just manipulate it with jQuery and JS.
To change the onClick for all the class='product-card', you can do something like this:
// All the links
const links = document.getElementsByClassName('product-card');
// Loop over them
Array.prototype.forEach.call(links, function(el) {
// Set new onClick
el.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
});
<div class="product-card " onclick="location.href='https://www.google.com'">Test</div>
Will produce the following DOM:
<div class="product-card " onclick="location.href = 'http://www.live.com/'">Test</div>
Another option, is to loop over each <div> and check if something like google.com is present in the onClick, if so, we can safely change it without altering any other divs with the same class like so:
// All the divs (or any other element)
const allDivs = document.getElementsByTagName('div');
// For each
Array.from(allDivs).forEach(function(div) {
// If the 'onClick' contains 'google.com', lets change
const oc = div.getAttributeNode('onclick');
if (oc && oc.nodeValue.includes('google.com')) {
// Change onClick
div.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
}
});
<div class="product-card" onclick="location.href='https://www.google.com'">Change me</div>
<div class="product-card">Don't touch me!</div>
I'm using the jQuery UI plugin fieldchooser and I want to know whenever the list changes so that I can update it in the database. The plugin has a listChanged function, but I'm not sure how to make it work. I working off this example:
<script>
$(document).ready(function () {
var $sourceFields = $("#sourceFields");
var $destinationFields = $("#destinationFields");
var $chooser = $("#fieldChooser").fieldChooser(sourceFields, destinationFields);
});
</script>
<div id="fieldChooser" tabIndex="1">
<div id="sourceFields">
<div>First name</div>
<div>Last name</div>
<div>Home</div>
<div>Work</div>
<div>Direct</div>
<div>Cell</div>
<div>Fax</div>
<div>Work email</div>
<div>Personal email</div>
<div>Website</div>
</div>
<div id="destinationFields">
</div>
</div>
Elsewhere on stack overflow, I found this example:
$chooser.on("listChanged",function(event,selection,list){
//event <- The jQuery event invoking the callback.
//selection <- The field (or set of fields) which has moved.
//list <- The field list to which the selection has moved.
alert("listChanged");
}
and have tried this, without success:
$chooser.on("listChanged",function(mouseup,sourceFields,destinationFields){
alert("listChanged");
});
I'd appreciate any suggestions on making this work. Thanks.
With correct code, this works as expected.
Working Example: https://jsfiddle.net/Twisty/v2Lrm9wq/2/
JavaScript
$(function() {
var $chooser = $("#fieldChooser").fieldChooser();
var $sourceFields = $("#sourceFields").children();
$chooser.getSourceList().add($sourceFields);
$chooser.on("listChanged", function(event, selection, list) {
alert("listChanged");
});
});
I've written my own jQuery clicking function, but for an unkown reason, it doesn't work. I get error on line 4.
for (var i = 1;i<=3;i++){
$("#Block"+i).click(function(){
$(this).effect("shake", function(){
if (this == "#Block3"){
window.open('contact.html','blank');//open link link in a new page
}
});
});
}
Could you please help me?
Explanation
this on line 4 returns (or is) an object, it is a DOM element (such as <div> or something like that) You can't compare object this and string "#Block3".
These two things are very different. It is like comparing pears and apples.
Take a look at JavaScript Data Types I think, it could help you.
Documentation
See the documentation of this object.
Getting ID of an element How can I get the ID of an element using jQuery?
Edit of your code
You have to get the ID of the object (this) and then compare it with the string "Block3"
for (var i = 1; i <= 3; i++) {
$("#Block" + i).click(function() {
$(this).effect("shake", function() {
if (this.id == "Block3") {
window.open('contact.html', 'blank'); //open link link in a new page
}
});
});
}
Edit of your code 2
jQuery is here to help you to do less of code. Take a while to look at some tutorials.
Your code could be shortened to something like this
$('.blocks-container').on('click', '.block', function() {
$(this).effect('shake', function() {
if (this.id == 'Block3')
window.open('contact.html', 'blank'); //open link link in a new page
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="blocks-container">
<div id="Block1" class="block">Block1</div>
<div id="Block2" class="block">Block2</div>
<div id="Block3" class="block">Block3</div>
<div id="Block4" class="block">Block4</div>
<div id="Block5" class="block">Block5</div>
</div>
With unlimited number of "Blocks". See Rory's answer!
.click vs .on
Also please learn to use
$('.blocks-container').on('click', '.block', function() {});
Instead of
$('.block').click(function() {});
Explanation here I think, that you will understand later.
Edit of your code 3
Or you can base your function on "Block" div index (= number of place under the parent element) instead of index. So you don't have to use ID for each of blocks.
$('.blocks-container').on('click', '.block', function() {
$(this).effect('shake', function() {
if ($(this).index('.block') == 2)
window.open('contact.html', 'blank'); //open link link in a new page
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="blocks-container">
<div class="block">Block1</div>
<div class="block">Block2</div>
<div class="block">Block3</div>
<div class="block">Block4</div>
<div class="block">Block5</div>
</div>
Love jQuery. Peace!
this in your code is a DOMElement. When coerced to a string it will never match #Block3, hence your if condition never hits.
Assuming you're trying to match the id of a specific element, then you just need to compare against the id property of this:
(var i = 1; i <= 3; i++){
$("#Block" + i).click(function(){
$(this).effect("shake", function(){
if (this.id === "Block3") {
window.open('contact.html', 'blank');
}
});
});
}
Also note that it would be much better practice to put a common class on all the #BlockX elements and use a single event handler on all of them:
$('.block').click(function() {
$(this).effect("shake", function(){
if (this.id === 'Block3')
alert('you clicked block3!');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="Block1" class="block">Block1</div>
<div id="Block2" class="block">Block2</div>
<div id="Block3" class="block">Block3</div>
<div id="Block4" class="block">Block4</div>
<div id="Block5" class="block">Block5</div>
Is there any jQuery event that fires when a class is added to some object, which can tell me what is the element's content?
let me explain using an example.
Let's say I have a series of divs, all having the same class but different content.
<div class="block">content a</div>
<div class="block">content b</div>
<div class="block">content c</div>
<div class="block">content d</div>
At some moment, one of them will get an additional class, let's say selected:
<div class="block">content a</div>
<div class="block">content b</div>
<div class="block selected">content c</div>
<div class="block">content d</div>
I can't know whitch one id the selected one. So I want to run a function when one of these items gets the selected class and I want that function to receive the content of the selected element.
$('.block').on('event?', function(content){
//content is equal to "content c"
});
Is there something like that available in jQuery? Can I create one?
I have a plugin for you.
Insert this into you script:
//#Author Karl-André Gagnon
$.hook = function(){
var arg = Array.prototype.slice.call(arguments)
$.each(arg, function(){
var fn = this
if(!$.fn['hooked'+fn]){
$.fn['hooked'+fn] = $.fn[fn];
$.fn[fn] = (function(){
this['hooked'+fn].apply(this, arguments);
this.trigger(fn, arguments);
})
}
})
}
Then activate it like that:
$.hook('addClass');
This will add an "event launcher" on add class.
Then bind it on you block :
$('.block').on('addClass', function(e,a){ //e == events a == first arguments when calling addClass()
if(a === "selected"){//Just a validation
//Your code
}
})
You can get its text using this:
$('element').text();
This will provide you with the text of the element!
For you, this would be
$('.selected').text();
Now you can show it as an alert, or write it somewhere or use it as a variable! It will have the value of
content c
Or what ever the value the element would provide you with!
For more: http://api.jquery.com/text/
function test(someClass){
var content;
if($('.block').hasClass(someClass)) {
content = $('.' + someClass).html();
}
}
Then you call the function with the class of your wish as a parameter: test('classname');
I looked at the post jQuery: Loop iterating through numbered selectors? and it didn't solve my problem, and didn't look like it was truly an answer that works.
I have a list of <h3> tags that are titles to questions, and there are answers below in a <p>. I created classes for each Q & A like so:
<h3 class="sec1">Question:</h3><p class="view1">Answer...</p>
<h3 class="sec2">Question:</h3><p class="view2">Answer...</p>
<h3 class="sec3">Question:</h3><p class="view3">Answer...</p>
I used the following jQuery loop to reduce redundacy for my 21 questions.
$(document).ready(function () {
for (var i = 1; i < 21; i++) {
var link = ".sec" + i;
var content = ".view" + i;
$(link).click(function () {
$(content).toggle("fast");
});
}
});
But it isn't working for all Q & A sets, only the last one. i.e.: It works for the first set if I set the max value to 2 (only looping once). Please advise. Thanks
While I agree with #gaffleck that you should change your approach, I think it is worth while to explain how to fix the current approach.
The problem is that the click function does not get a copy of the content variable but instead has a reference to that same variable. At the end of the loop, the value is .view20. When any element is clicked it read that variable and gets back .view20.
The easiest way to solve this is to move the code into a separate function. The content variable within this function is a new variable for every call of the function.
function doIt(i){
var link = ".sec" + i;
var content = ".view" + i;
$(link).click(function () {
alert(content);
});
}
$(document).ready(function () {
for (var i = 1; i < 21; i++) {
doIt(i);
}
});
http://jsfiddle.net/TcaUg/2/
Notice in the fiddle, if you click on a question the alert has the proper number. Optionally, you could make the function inline, though I find the separate function in most cases to be a bit cleaner.
http://jsfiddle.net/TcaUg/1/
A much easier way to do this, would be this:
$(document).ready(function(){
$("h3").click(function(){
$(this).next("p").toggle("fast");
});
});
This is also safer in that you can add/remove questions and answers in the future and you won't have to update the function.
Wrap your questions in a more logical structure to create a proper scope for your questions-block:
<div id="questions">
<div class="question">
<h3 class="sec1">Question:</h3><p class="view1">Answer...</p>
</div>
<div class="question">
<h3 class="sec2">Question:</h3><p class="view2">Answer...</p>
</div>
<div class="question">
<h3 class="sec3">Question:</h3><p class="view3">Answer...</p>
</div>
</div>
Now iterate through it like this:
$(function() {
$('#questions .question h3').click(function(){
$(this).parent().find('.answer').toggle('fast');
});
});