I defined this function which checks if a input field is empty or not
function hasValue() {
if ( !!$.trim( $(this).val() ) )
return true;
}
It just works fine for filtering a jQuery Collection
$('#form').find( '.email' ).filter( hasValue );
But I also want to reuse the hasValue()-function for toggeling a class.
$('.input').change( function () {
var empty = hasValue().apply( $(this) ); //throws an error
// var empty = $(this).hasValue(); //doesn't work either
$('#box').find('.required-tmp').toggleClass('required', empty );
});
Any help is appreciated.
Juste pass this to apply. And don't execute () before :
hasValue.apply(this);
If you want to have a better use of your function it must accept an element as parameter it's not a good pattern to use this like this. Prefer to pass the element in arguments
function hasValue(elem) {
return !!$.trim($(elem).val());
}
And then the usage is the same for map :
$('#form').find( '.email' ).filter( hasValue );
And :
$('.input').change( function () {
var empty = hasValue(elem); //throws an error
$('#box').find('.required-tmp').toggleClass('required', empty );
});
$('.input').change( function () {
var empty = hasValue.apply( $(this) ); //apply function should be used this way .
// var empty = $(this).hasValue(); //doesn't work either
$('#box').find('.required-tmp').toggleClass('required', empty );
});
Why are you using double negation in the hasValue method?
Secondly, use apply as:
var empty = hasValue.apply( this );
This will pass the element as the parameter which you can use there!
Thirdly, for checking whether the value exists, you can just use type check instead of trim as:
if(typeof $(this).val !== 'undefined'){
return true;
}
See if that works for you!
fn.apply syntax should be like hasValue.apply( $(this) ) instead of hasValue().apply( $(this) )
May be that will solve your problem.
Thanks & Regards,
Charly
Related
So I have the following problem at hand;
I want to getText from a registrationNumber. so I defined a var regNumber = null;
I defined the var in global.js because I want to access the var throughout the whole test with different pageObjects and outside of a specific function.
When it gets the text and it needs to fill in the text with setValue in the Template Search it returns Object Object, so I tried to use toString but is the same.
this is the function which I need to use in order to use the var
module.exports = {
var regNumber = browser.globals;
Page Object
openSearch: function(browser, regNumber ) {
browser.perform(function () {
browser.waitForElementVisible('.registrationnumber-search input', 3000)
browser.setValue('.registrationnumber-search input', regNumber )
return this;
})
Test
.continueButton()
browser.getText('xpath', '//*[#id="wizardDetailsTab"]/div[1]/div/div[1]/h4/span[2]', function (result) {
regNumber = result.value
console.log(result.value)
})
certificateEditor
.quickMenu("Permit")
.createNewItem("template")
permit
.openSearch(browser, regNumber)
The console.log(result.value) returns the value which I want, however it does not work when I want to use that value in setValue. If I create a function and do the getText in that scope, it fills in what I need. BUt I want to know why it does not work when I try it like this.
Thanks in advance!
in your page object :
openSearch: function(regNumber ) {
return this.perform(function (done) {
this.api.waitForElementVisible('.registrationnumber-search input', 3000)
.setValue('.registrationnumber-search input', regNumber )
done(); //prevent timeout issue
})
Move the code after getText() into it.
var permit=client.page.permit() // replace .permit() as .yourpageobjectjsname()
.....
.continueButton()
browser.getText('xpath', '//*[#id="wizardDetailsTab"]/div[1]/div/div[1]/h4/span[2]', function (result) {
regNumber = result.value
console.log(result.value)
certificateEditor
.quickMenu("Permit")
.createNewItem("template")
permit
.openSearch(regNumber)
})
From the looks of it what's happening is you're returning an Object, when you're looking for a string. I think you just need to designate the object you want.
browser.globals
should be something like
browser.globals.value or browser.globals.text
Your browser.globals is the object being returned. You have to specify what key/value pair you want that object to return.
I have vars that look like this:
var cardholder = $("#cardholder");
var cardholderInfo = $("#cardholder-Info");
And a function (which doesn't currently work) that looks like this:
function validateRequired(field){
//if it's NOT valid
if(field.val().length < 1){
field.addClass("field_error");
fieldInfo.text("(Required)");
fieldInfo.addClass("error");
return false;
}
//if it's valid
else{
field.removeClass("field_error");
fieldInfo.text("");
fieldInfo.removeClass("error");
return true;
}
}
Which I access like:
cardholder.keyup(validateRequired(cardholder));
I've looked everywhere but I can't find what I need and I'm not really sure what I should be searching for.
I can use the field value to access the straight cardholder var. But I also want to use the field value to then reference cardholderInfo so I can manipulate that element in the function.
You would call the function like this, passing the second parameter:
cardholder.keyup(function () {
validateRequired(this, cardholderInfo);
});
And modify your function to take a second parameter:
function validateRequired(field, fieldInfo){
/* validation stuff */
}
No need for the global variables:
function validateRequired($cardInfo){
// You can guess what $cardInfo is
//if it's NOT valid
if(this.val().length < 1){
this.addClass("field_error");
$cardInfo.text("(Required)");
$cardInfo.addClass("error");
return false;
}
//if it's valid
else{
this.removeClass("field_error");
$cardInfo.text("");
$cardInfo.removeClass("error");
return true;
}
}
$(document).ready(function(){
$("#cardholder").keyup(function(){
validateRequired.call($(this),$("#cardholder-Info"));
});
});
Don't call the function you want to bind! If you need to pass an argument to it every time it is called, you either need to use bind or a function expression:
cardholder.keyup(functio(e) {
return validateRequired(cardholder, cardholderInfo);
});
Also you will need a second parameter in your validateRequired function to get the fieldInfo variable filled:
function validateRequired(field, fieldInfo){
…
You have to pass reference of function in keyup, you do not have to call function
cardholder.keyup(function(){
validateRequired(cardholder)
});
I just want to share an experience with you all. So my problem was, that I came across the problem of binding javascript back-end objects to HTML front-end elements. Now, i have searched through google and read some stackoverflow articles about this problem, and many posts answer to this is to use jQuery.data(), however in my first attempts I did not succeed because there was something I did not know about jQuery's object creation method. My problem was that, I wanted to retrieve the stored data outside of the scope where i stored this, and jQuery always(i think) returns a new object reference when i write jQuery('selectorID'). So for example:
var ref1 = $('#myID');
var ref2 = $('#myID');
if(ref1 == ref2)
{
alert(true);
}
else
{
alert(false);
}
Will always alert false. However replacing the jQuery method with javascript's built-in getElementById() we will get the same reference! Hence the following code will always alert true!
var ref1 = document.getElementById("myID");
var ref2 = document.getElementById("myID");
if(ref1 == ref2)
{
alert(true);
}
else
{
alert(false);
}
The little morale of my story is that if you want to globally bind javascript objects to HTML elements and are thinking about using jQuery's data() method, store the data on the reference returned by javascript's built-in getElementById(). That way, whereever you retrieve the reference with getElementByID, you will always get the same reference and can get the data from it using jQuery's data() method.
My Questions:
Is my logic of thinking ok?
Is there a better way to globally bind javascript objects to HTML elements?
Whatever the reason behind the code you mention not working was, it was decidedly not the fact that jQuery gives you a new collection for every query. Given the HTML:
<div id="somediv"> foo bar </div>
the following Javascript works as expected:
var $ref1 = $('#somediv');
var $ref2 = $('#somediv');
console.log("$ref1:", $ref1);
console.log("$ref2:", $ref2);
// compare the collections / references
console.log("$ref1 == $ref2:", $ref1 == $ref2); // => false
console.log("$ref1 === $ref2", $ref1 === $ref2); // => false
// compare the referred DOM elements themselves
console.log("$ref1[0] == $ref2[0]:", $ref1[0] == $ref2[0]); // => true
console.log("$ref1[0] === $ref2[0]", $ref1[0] === $ref2[0]); // => true
$ref1.data('somedata', 'SOMEDATA');
console.log('$ref1->somedata:', $ref1.data('somedata')); // => SOMEDATA
console.log('$ref2->somedata:', $ref2.data('somedata')); // => SOMEDATA
The way I do it is something like this.
var ref1 = $('a');
var ref2 = $('div');
var equal = ref1.length === ref2.length;
if (equal) {
$.each(ref1, function(i) {
equal = equal && ref1[i] === ref2[i];
if (!equal) {
return false;
}
});
}
if (equal) {
alert(true);
} else {
alert(false);
}
ref1[0] === ref2[0] // Should return true
I think jQuery's instances are unique, so you can compare its matched items, which should be just one element when you reference an ID.
You could do something like this:
var ref1 = $('#myID')[0];
var ref2 = $('#myID')[0];
I dive into jQuery's source code, and find the constructor of jQuery. As follow:
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
Whenever you use ref2 = $('#myID') to retrive a corresponding jQuery element, jQuery will create a new object to you. So the == will return false to you coz' the two element is completely different to js object engine.
Seems getElementById method is more fit your need. But I don't know how js engine perform its getElementById method.
Hello everyone.
I am trying to develop a Jquery plugin following the steps I found in http://docs.jquery.com/Plugins/Authoring and I seem to have problems reaching the caller object (the “this” variable) inside the options passed to the plugin. It is a plugin that I just want to use to make a button have a “blink” effect.
I would like to be able to pass the functions to execute in “show/hide” (or link blink-on, blink-off, if you prefer) as an option for the plugin. Let's say the user wants to achieve the “blinking” effect by hiding/showing the whole button every 1000 milliseconds. Then I would like the options to be something like:
$("#bttnOk").myBlinker ({
blinkHide: function(){$(this).hide();},
blinkShow: function(){ $(this).show();},
interval:1000
});
// … //
// And to make it actually blink:
$("#bttnOk").myBlinker ("blink");
Or let's say that the user wants to move the button up and down applying an inline css sytle every 200ms. Then the options would something like:
$("#bttnOk").myBlinker ({
blinkHide: function(){$(this).css(“margin-top: 10px”);},
blinkShow: function(){ $(this).css(“margin-top: 0px”);},
interval:200
});
The problem is that I seem to lose the reference to “$(this)” when I am inside the options. When the plugin reaches the blinkHide/blinkShow functions, “this” is the whole DOM window, not the button $(“#bttnOk”) my “myBlinker” plugin is attached to.
This is the first Jquery plugin I'm trying to write so I'm not even sure if there's a way to achieve what I'm trying to do.
My plugin code follows the following structure:
(function($){
var defaultOptions = {
interval: 500
}
var methods = {
init : function( options ) {
return this.each(function(){
this.options = {}
$.extend(this.options, defaultOptions, options);
var $this = $(this);
var data = $this.data('myBlinker');
// If the plugin hasn't been initialized yet
if ( ! data ) {
$this.data('myBlinker', {
on : true
});
}
});
},
destroy : function( ) { // Some code here},
blink: function ( ){
console.log("Blinking!. This: " + this);
var current = 0;
var button=this.get(0);
setInterval(function() {
if (current == 0){
button.options["blinkShow"].call(this);
current=1;
} else {
button.options["blinkHide"].call(this);
current=0;
}
}, button.options["interval"]);
}
};
$.fn. myBlinker = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.myBlinker ' );
return null;
}
};
})(jQuery);
Any idea, correction, link or tip will be appreciated.
Thank you.
Within the setInterval function, this is the global object, not the current element DOMElement like in the blink function.
A solution to that is to save a reference of this and use this saved reference in the setInterval:
blink: function ( ){
// save a reference of 'this'
var that = this;
setInterval(function() {
// use the saved reference instead of 'this'
button.options["blinkShow"].call(that);
}, button.options["interval"]);
}
DEMO
First of all I don't know how to phrase the question "title", sorry if I am confusing everyone with the title here.
Anyway, I saw this code at jQuery http://docs.jquery.com/Plugins/Authoring
(function( $ ){
var methods = {
init : function( options ) {
return this.each(function(){
var $this = $(this),
data = $this.data('tooltip'),
tooltip = $('<div />', {
text : $this.attr('title')
});
// If the plugin hasn't been initialized yet
if ( ! data ) {
/*
Do more setup stuff here
*/
$(this).data('tooltip', {
target : $this,
tooltip : tooltip
});
}
});
},
destroy : function( ) {
return this.each(function(){
var $this = $(this),
data = $this.data('tooltip');
// Namespacing FTW
$(window).unbind('.tooltip');
data.tooltip.remove();
$this.removeData('tooltip');
})
},
reposition : function( ) { // ... },
show : function( ) { // ... },
hide : function( ) { // ... },
update : function( content ) { // ...}
};
$.fn.tooltip = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.tooltip' );
}
};
})( jQuery );
My question being is that I cannot understand why do we need this if statement?
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
}
Or in other words, in what scenario that we will pass in argument like "methods[method]" base on the example?
Thanks!
That if statement will check if you are trying to call one of the methods available to the plugin. In the case of you example you have these methods:
init, destroy, reposition, show, hide, and update
So you can do a call like :
$.tooltip('init', { arg1: true, arg2: 'a value' });
Then your code knows where to send the arguments because this if statement will be true:
if(methods['init'])
You see at the beginning that the code defines an object methods.
The function $.fn.tooltip = function( method ) accepts an argument with name method (no s at the end).
The function will execute one of the methods defined in methods, but it can only do it, if this method is also available. Hence the if(methods[method]).
The expression will be true if method is e.g. show, hide, update, etc, i.e. if the methods object has a property with the name contained in method.
Therefore the expression will be false for foo or bar. If the if statement would not be there, the code would try to call method['foo'], which does not exist and you would get an error:
TypeError: object is not a function
Is this what you wanted to know?
Your code snippet isn't complete and it doesn't contain a demo to show how it's called, so it's hard to give a definite answer.
However, here's what I think from what the code looks like:
The if statement is necessary because the tooltip function will be called with arguments such as init, destroy, show, hide, update, which refer to the functions defined in the methods hash. You probably call tooltip with init to initialize the tooltip, hide to hide it, show to show it etc. If you don't pass an argument at all, it defaults to the init method and initializes the tooltip (second branch of the if).
First of all, the piece of code declares an hashmap named methods which contains some functions.
Then, the second part declares a function named tooltip which takes a parameter named method. This parameter is the name of the function we want to call, this name is the index of this function in the methods array.
So, when you do $('#whatever').tooltip('destroy'); it will look in the methods array for the function referenced with the destroy key.