this.prop is not a function? - javascript

My jQuery code is:
$('#edit').click(function(){
var data = $("#list :input").serialize();
$.post($("#list").attr('action'), data, function(json)
{
currentRow = json.rowArr[0];
$("#id").val(currentRow.id);
$("#id_disp").val(currentRow.id);
$("#shop").val(currentRow.shop);
$("#category").val(currentRow.category);
$("#item").val(currentRow.item);
$("#qnty").val(currentRow.qnty);
$("#unit").val(currentRow.unit);
$.each($("#price_based_on").children('option'), function(index, val) {
if(this.value.toUpperCase()==currentRow.price_based_on.toUpperCase())
{
console.log("Match");
this.prop("selected", true);
}
});
$("#mrp").val(currentRow.mrp);
$("#sellers_price").val(currentRow.sellers_price);
$("#last_updated_on").val(currentRow.last_updated_on);
},"json");
});
Among this, the only thing of interest are the lines:
$.each($("#price_based_on").children('option'), function(index, val) {
if(this.value.toUpperCase()==currentRow.price_based_on.toUpperCase())
{
console.log("Match");
this.prop("selected", true);
}
});
On using the statement this.prop("selected", true); I get the error:
Uncaught TypeError: this.prop is not a function
Why does this happen when .prop() is clearly a function that exists? How do I fix it?

$.each is used to iterate over an object or array. If you want to iterate over the nodes in a jQuery object, use .each like this:
$("#price_based_on").children('option').each(function() {
... code here
});
Inside the call back, this refers to the native DOM element (which doesn't have a prop method, so you probably want to do something like this to get a reference to the jQuery object that holds the DOM node:
$("#price_based_on").children('option').each(function() {
var $this = $(this);
$this.prop('selected',true)
});

this is not a jquery object, you need to add jquery selector $() around to make it jquery object, so change it to $(this).

this is not a jQuery object. Use $(this)
$(this).prop("selected", true);

Related

jQuery: apply function to elements at the same time

With jQuery.each(), I can iterate through members of the array:
// This is NOT what I am looking for.
$('.example a').each(function() {
// do a lot of things here
$(this).css('color', 'red');
});
However, I need to apply a function to the jQuery array itself, and not to its members. So I wrote a little plugin to do this:
$.fn.all = function( callback ) { return callback.call( this ); }
$('.example a').all(function() {
// do a lot of things here
$(this).css('color', 'red');
});
Please notice that in the function above, this will be set to the collection of the elements - which is what I require.
Now I'm sure that jQuery should have an elegant way to do this, but I haven't found anything in the documentation, or by Googling.
Is it possible, and if it is, how do I achieve this without using custom plugins?
UPDATE: I can not do $('.example a').css('color', 'red'); directly. I have a dozens of calculations in the function, so I have to use something similar to the plugin I wrote.
I am asking for a callback. The correct answer must provide a callback similar to the custom function.
You don't need a plugin, you can use call directly:
(function() {
// do a lot of things here
this.css('color', 'red');
}).call($('.example a'));
Or consider passing the array-like object as an argument
(function(arrayLike) {
// do a lot of things here
arrayLike.css('color', 'red');
})($('.example a'));
Or if you prefer a jQuery way
$.each([$('.example a')], function(){
// do a lot of things here
this.css('color', 'red');
});
Shouldn't
$('.example a').css('color', 'red');
be enough?
That would be the straight-forward (jQuery-esque) way to do what you want:
var $collection = $('.example a');
$collection.each(function() {
// do a lot of things here
$collection.css('color', 'red');
});
//And another reason I dislike jQuery's implementation of each().
//but most of all, wrong argument-order and the abuse of this to pass the current value/node
Here my prefered implementation. Mostly like Array.prototype.forEach(), and the nice parts of $.each().
$.fn.forEach = function(fn, scope){
if(scope != null) fn = fn.bind(scope);
for(var i = 0, len = this.length; i < len; ++i)
if(false === fn(this[i], i, this)) break;
return this;
}
and your code would be like:
$('.example a').forEach(function(node, index, $collection){
//and don't use `$(this)`, since `this` most of the time references `window`
//unless you've bound the function to a scope, or passed one to forEach
var $node = $(node);
$collection.css('color', 'red');
});
this
$('.example a')
returns collection of matched elements. And this
$('.example a').css('color', 'red');
sets color red to all elements in the collection.
That's how jQuery works.
I think that is not possible getting all the calculations at the same time, you should use threads for that, or a webWorker. You can get more info about this in mdn.
You can cache selector, utilize $.queue()
var elems = $(".example a");
$.queue(elems, "q", function() {
$(this).css("color", "red");
console.log(this)
});
$.dequeue(elems, "q")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="example">
a
b
c
</div>

jQuery.each() - passing extra argument to the callback parameter

This is a fragment of a plugin that I'm using on my site:
$.fn.extend({
limiter: function(limit, elem) {
$(this).on("keyup focus", function() {
setCount(this, elem);
});
function setCount(src, elem) {
...
}
}
});
The setCount() function works well only if the elem property in not an array - only single values are accepted.
I'd like to change it so that I can pass arrays (multiple selection in my case) to the setCount() function.
I thought that a solution would be to use jQuery.each() iterator like so:
$.fn.extend({
limiter: function(limit, elem) {
$(this).on("keyup focus", function() {
$.each(elem, setCount)
});
function setCount(src, elem) {
...
}
}
});
The problem is that I also have to pass the this object which points to the object that received "keyup focus" as is the case in the first snippet.
How do I pass this object to the callback property of $.each() in the given scenario?
Try binding the context, using bind (warning not IE8 compatible):
$.each(elem, setCount.bind(this))
This makes the this-context inside each setCount-call, pointing to this from the event handler.
You can keep a reference to the "first" this and use it in setCount:
$.fn.extend({
limiter: function(limit, elem) {
var that = this;
$(this).on("keyup focus", function() {
$.each(elem, setCount)
});
function setCount(src, elem) {
// use 'that' here
...
}
}
});

Object #<HTMLDivElement> as jQuery object

How can I get a #<HTMLDivElement> as a jQuery object?
I need to do the following: I have a list of div's with the class contents. So I iterate over it until I find the one with the additional class: "test"
here is my code:
$.each( $(".contents"), function( key, value ) {
if (value.hasClass("test"))
{
alert("got it");
}
});
I'm getting the exception: Uncaught TypeError: Object #<HTMLDivElement> has no method 'hasClass'
The each() function gives you DOM object and you have to convert it to jQuery object. You can pass value to $ jQuery function to convert it to jQuery object.
$.each( $(".contents"), function( key, value ) {
if ($(value).hasClass("test"))
{
alert("got it");
}
});
You do not need to iterate through each and simplify it like
elements = $(".contents.text")
Why not to do it simpler with:
$(".contents.test"). ...
Here jQuery will select element that has both "contents" and "test" classes set.
DEMO: http://jsfiddle.net/xfErG/
The main jQuery function can accept a DOM Element as its argument.
var foo = jQuery(HTMLElementNode);
The following two lines of code have the same end result:
var foo = jQuery('#foo');
var foo = jQuery(document.getElementById('foo'));

jQuery - why can't I bind events to elements in a loop?

Here is my code:
var b = $(slipStream.conf.mainVis).find('p#prev');
b.click(function() {
slipStream.slideLeft();
return false;
});
b = $(slipStream.conf.mainVis).find('p#next');
b.click(function() {
slipStream.slideRight();
return false;
});
b = $(slipStream.conf.controls).find('li img');
console.log(b);
for (var l in b) {
l.click(function() {
var visIndex = l.index();
console.log(visIndex);
});
};
The first two bindings go through, no problem. But I can't loop through a collection and bind something to each member? (the console is telling me that "l.click is not a function.") Is this a limitation of jQuery or is my code off? This seems like it would be the way to do it, though...
When you enumerate over a jQuery object, the values being enumerated are actual DOM nodes and not jQuery wrappers. Therefore, they don't have a click method but you can wrap them again to get all the usual functionality.
Of course this is not necessary because you can simply attach a wrapper directly from your initial jQuery instance:
$(slipStream.conf.controls).find('li img').click(function() {
var visIndex = $(this).index();
console.log(visIndex);
});
This is the classic "loop variables don't work properly in callbacks" bug.
Your variable l no longer has the originally supplied value by the time the callback is invoked - it has whatever final value was assigned in the last pass through the loop.
[FWIW, l isn't actually a jQuery object, so you have to wrap it - $(l) to use it with jQuery]
The usual fix to the loop bug is to create an additional closure that returns a function bound to the current value:
for (var l in b) { // NB: don't use `for ... in ...` on array-like objects!
var make_cb = function(n) {
return function() {
var visIndex = $(n).index();
console.log(visIndex);
}
}
$(l).click(make_cb(l));
};
Fortunately, you don't need a loop at all - you can have jQuery automatically add the callback to every element by itself:
b = $(slipStream.conf.controls).find('li img');
b.click(function() {
var visIndex = $(this).index();
console.log(visIndex);
});
Could it be that the problem is the forloop. .click is part of the jQuery, so you must be sure that it's called on element that is wrapper with jQuery.
$.each(b, function (index, element) {
$(element).click(function() {
});
};
With each() you can iterate through a set of jQuery objects:
$(slipStream.conf.controls).find('li img').each(function(){
$(this).click(function() {
var visIndex = $(this).index();
console.log(visIndex);
});
});
$(this) will match the currently indexed object from the collection.

remove elements from the jQuery object from within a plugin

I think I have mistaken some fundamentals here, because I think this should work. I am trying to to through the child p and div elements of the matched set, and remove those which fail to meet the required wordcount from the matched set.
I have tested the wordCount plugin, and the if statement it is being used it, and all seems to be working fine, but my element is not being removed from the matched set.
(function($){
$.fn.extend({
textBlocks: function(count){
var JQ_Object = $(this);
if(!count) count = 100;
return this.each(function(){
$(this).find("p, div").each(function(){
if($(this).wordCount()<count){
var x = $(this);
JQ_Object.not(x);
};
});
return JQ_Object;
});
}
});
})(jQuery);
Here is the wordCount plugin, just in case you wondered:
(function($){
$.fn.extend({
wordCount: function(){
return $(this).html().split(" ").length;
}
});
})(jQuery);
I made a few changes... see fiddle for working example and code for comments.
http://jsfiddle.net/8PXpt/
(function ($){
$.fn.extend({
wordCount: function (){
//Don't need $(this), this already refers to the jQuery object
//Always trim .html() and .text() when using .split()
//May want to use .text() instead of .html() - I leave that to you
return $.trim(this.html()).split(' ').length;
}
});
})(jQuery);
(function ($){
$.fn.extend({
textBlocks: function (count){
var collection = this;
//Check that a number was passed
//"50" would break your extension
if(typeof count !== 'number') {
count = 100;
}
//Removed $('div, p') - this should be part of your call
//See ready function below
this.each(function (){
if ($(this).wordCount() < count){
//This could be double assignment
//but better safe than sorry
collection = collection.not(this);
};
});
//Return what is left (what passed)
return collection ;
}
});
})(jQuery);
$(function() {
//Here is where you define your selector... in your case 'div, p'
$('div, p').textBlocks(2);
});
Have you tried $(this).remove() rather than JQ_Object.not(x);
I think .not() removes them from the selection rather than from the HTML... unless that's what you're trying to do
You're creating a new JQ_Object in the internal each, so I'm not sure if it would modify the original JQ_Object. I'm not 100% on that though. Try JQ_Object.not(this).
This assumes, however, that .each is synchronous, which I'd hope it isn't. If that's the case, you'd need to make use of jQuery's while function.
This should give you the desired result, but I'd be wary each being asynchronous.
return $(this).find("p, div").each(function(){
if($(this).wordCount()<count){
JQ_Object.not(this);
};
});
EDIT:
I'm not to sure about the above code. What I'd do is use a callback. This assumes a callback is passed in to your plugin.
$(this).find("p, div").each(function(){
if($(this).wordCount()<count){
JQ_Object.not(this);
};
}).when(function () {
callback(JQ_Object);
});

Categories

Resources