for loop is not working in protractor - javascript

I have used the below for loop to click on the icon in 5th index of td, if the 2nd index of td contains text (which is passed as external parameter) as expected.
I'm getting the row elements as tenantRowElements and written the following code.
The outcome is reached i.e, the expected button is clicked but still am facing the below error and it is not moving into next method.
stale element reference: element is not attached to the page document
error.
this.clickEditOfTenant=function(userobj) {
console.log("Edit of tenant is clicked");
basePage.waitForElement(this.tenantRowElements, 5000);
this.tenantRowElements.then(function (tenants) {
console.log("element length : " + tenants.length);
for (var i = 0; i < tenants.length; i++) {
tenants[i].$$('td').then(function (tds) {
tds[1].getText().then(function (text) {
return text;
}).then(function (name) {
console.log("tenant name : " + name + "; given name :" + userobj.tname);
if (name === userobj.tname) {
tds[5].click();
}
});
});
}
}).then(function () {
if(basePage.isVisible(updateTenant.tenantNameTxtBox))
{console.log("Edit button is clicked");}
});
};

i have edited as below, and now its working
this.clickEditOfTenant = function(userobj) {
console.log("call clickEditOfTenant()");
basePage.waitForElement(this.tenantRowElements, 10000);
//browser.sleep(15000);
this.tenantRowElements.filter(function (tr) {
return tr.all(by.css('td')).get(1).getText().then(function (name) {
return name === userobj.tname;
});
}).then(function (eles) {
eles[0].$$('td').then(function (btn) {
//console.log(text);
btn[5].click();
}).then(function () {
browser.sleep(5000);
if (basePage.isVisible(updateTenant.tenantNameTxtBox)) {
console.log("Edit button is clicked");
}
});
});
};

I suspect basePage.waitForElement(this.tenantRowElements, 5000); is not sufficient to wait the page complete load. So you met the issue at the first iteration of loop,
Add browser.sleep(15000) after basePage.waitForElement(this.tenantRowElements, 5000); for debug purpose.
And you can use filter() to make your code briefness:
this.clickEditOfTenant = function(userobj) {
console.log("call clickEditOfTenant()");
// basePage.waitForElement(this.tenantRowElements, 5000);
browser.sleep(15000)
this.tenantRowElements.filter(function(tr) {
return tr.all(by.css('td')).get(1).getText().then(function(name) {
return name === userobj.tname;
});
})
.then(function(eles) {
if(eles.length > 0) {
eles[0].click();
}
})
.then(function () {
if(basePage.isVisible(updateTenant.tenantNameTxtBox)) {
console.log("Edit button is clicked");
}
});
};

Related

How to call a function in JavaScript when radio button is selected

I am new to JavaScript, I am trying to call another function but it is not working can someone tell me what am doing wrong. I have a radio button based on the selection i want to call a function.
const paymentForm = document.getElementById('paymentForm');
paymentForm.addEventListener("submit", myFunction, false);
//PaymentMethodRadio:
function myFunction() {
if (document.getElementById('Once').checked) {
payWithPaystack1.call();
}
if (document.getElementById('Reoccuring').checked) {
}
}
function payWithPaystack1(e) {
e.preventDefault();
let handler = PaystackPop.setup({
key: 'censored', // Replace with your public key
email: document.getElementById("email-address").value,
amount: document.getElementById("amount").value * 100,
ref: '' + Math.floor((Math.random() * 1000000000) + 1), // generates a pseudo-unique reference. Please replace with a reference you generated. Or remove the line entirely so our API will generate one for you
// plan: 'censored',
subaccount: 'censored',
// label: "Optional string that replaces customer email"
onClose: function () {
alert('Window closed.');
},
callback: function (response) {
let message = 'Payment complete! Reference: ' + response.reference;
alert(message);
}
});
handler.openIframe();
}
with If statement like this
if(document.getElementById('radioButtonID').checked) {
// do this
}
check this stack it may help
How can I check whether a radio button is selected with JavaScript?
Try to use on or changed events
$(document.getElementById('Reoccuring')).on('click change', function(e) {
// your checking statements.
if (document.getElementById('Reoccuring').checked) {
//checked function
} else
{
// unchecked
}
});

jQuery click function not attaching correctly

I'm trying to write a reusable bit of code for attaching scroll-to click events to various DOM nodes by using data attributes. Here's what I have so far:
HTML
<li class="scroll-to-anchor" data-dest='top'></li>
<div id='top'></div>
JS
if ($('.scroll-to-anchor').length) {
$('.scroll-to-anchor').each(function () {
var instance = $(this);
if ($(this).attr('data-dest')) {
var destination = $(this).data('dest');
if ($('#' + destination).length) {
instance.click(function () {
alert('click');
// Scroll to destination
})
} else {
throw 'Not a valid scroll-to anchor'
}
} else {
throw 'No data attribute present'
}
});
}
As you can see, the function is supposed to:
Check if any .scroll-to-anchor nodes exist
If they do, run them through an each
Check if .scroll-to-anchor has a data-dest attribute
If it does, check that the attribute corresponds to a DOM node
If it does, attach the click event
Everything is working fine, but the click event isn't attaching. I have a feeling this is scope related, but I can't figure it out...
throw may breaks your loop.
You may want to use console.error() instead.
$(".scroll-to-anchor").each(function() {
var instance = $(this),
destination = instance.data('dest'),
element = $("#" + destination);
if (destination) {
if (element) {
instance.on("click", function() {
console.info("Anchor clicked");
$('html, body').animate({
scrollTop: element.offset().top
}, 500);
});
} else {
console.error("Destination not found");
}
} else {
console.error("No destination specified");
}
});
check this JsFiddle
HTML
<a id="top"></a>
<div class="scroll-to-anchor" data-dest="top">sdlkjfs</div>
JS
$('.scroll-to-anchor').each(function () {
var instance = $(this);
if (instance.data('dest')) {
var destination = instance.data('dest');
if ($('#' + destination).length) {
instance.click(function () {
alert('click');
// Scroll to destination
})
} else {
throw 'Not a valid scroll-to anchor'
}
} else {
throw 'No data attribute present'
}
});

How to prevent browser.driver.sleep

I have the below spec which is working fine, but I want to prevent using browser.sleep():
it('should go to the item details page', function () {
browser.get(testOptions.baseUrl+testOptions.cpdmPath+testOptions.itemDetailsForAttachment);
browser.getCurrentUrl().then(function() {
//browser.driver.sleep('4000');
console.log('inside then 4');
browser.driver.sleep('4000');
element(by.css('.md-header-items-container')).isDisplayed().then(function (isVisible) {
if (isVisible) {
// element is visible
browser.driver.sleep('4000');
element.all(by.repeater('(key, value) in tabList')).count().then(function (numberOfTabs) {
//console.log(numberOfTabs);
});
element.all(by.repeater('(key, value) in tabList')).get(4).click().then(function () {
browser.driver.sleep('4000');
element(by.css('.hidden-attachment-info-bar')).isDisplayed().then(function (isVisible) {
expect(isVisible).to.equal(true);
})
});
} else {
// element is not visible
console.log('is invisible');
}
});
})
});
A common alternative to using sleep() with hardcoded time intervals is to use wait() and explicitly wait for a specific condition to be met. For example, wait for element to be visible:
var EC = protractor.ExpectedConditions;
var elm = element(by.css('.md-header-items-container'));
browser.wait(EC.visibilityOf(elm), 4000);
Finally, I got it working as below:
it('should go to the attachments page and pass waiting time for element', function() {
browser.get(testOptions.baseUrl+testOptions.cpdmPath+testOptions.itemDetailsForAttachment);
browser.wait(function() {
return browser.driver.isElementPresent(cpdmAttachTabPage.notificationBar);
}, 90000);
browser.driver.isElementPresent(cpdmAttachTabPage.notificationBar).then(function(isVisible) {
console.log(isVisible);
expect(isVisible).to.equal(true);
})
})

AngularJs+Bootstrap+Typehead+Ajax is working only if i put alert box but only in chrome

i am using bootsrap typehead with angularjs given at this link http://angular-ui.github.io/bootstrap/
In my controller
$scope.getUser = function(val) {
//alert("hi");
return $http.get('user/getUserNames.do', {
params: {
userName: val,
}
}).then(function(response){
return response.data;
});
};
my html code
<input type="text" ng-model="asyncSelected" typeahead-wait-ms="300" typeahead="user for user in getUser($viewValue)" class="form-control">
if remove the alert the typehead will not work
if i keep the alert the typehead will work only in chrome
if i place a break point at "return $http.get('user/getUserNames.do'" and step out using
fire bug it works in firefox
i am receiving the data in this formate ['name1','name2'] from server
some one please help
thanks in advance
thats because the time taken to close the alert the async data is recieved. you should store the data on $scope rather then calling a function on $scope
$scope.users= {};
$scope.getUser = function(val) {
return $http.get('user/getUserNames.do', {
params: {
userName: val,
}
}).then(function(response){
$scope.users= response.data;
});
};
html
<input type="text" ng-model="asyncSelected" ng-change="getUser($viewValue)"
typeahead-wait-ms="300" typeahead="user for user in users" class="form-control">
your cods logic is incorrect,you cant return data like that from a async function, that need time to complete,
dont return anything from this getUser function. you have 2 option :
1 - store the responce.data in a global variable to be used later
$scope.users = [];
$scope.getUser = function (val) {
$http.get('user/getUserNames.do', {
params: {
userName: val
}
}).then(function (response) {
$scope.users.push(response.data);
});
};
2 - call another function when get function is complete to handle the data recived
$scope.getUser = function (val) {
$http.get('user/getUserNames.do', {
params: {
userName: val
}
}).then(function (response) {
$scope.userLoaded(response.data);
});
};
By the simple hack in angular-ui-bootstrap i solved the problem
before..........
var getMatchesAsync = function(inputValue) {
var locals = {$viewValue: inputValue};
isLoadingSetter(originalScope, true);
$q.when(parserResult.source(originalScope, locals)).then(function(matches) {
//it might happen that several async queries were in progress if a user were typing fast
//but we are interested only in responses that correspond to the current view value
var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
if (onCurrentRequest && hasFocus) {
if (matches.length > 0) {
scope.activeIdx = focusFirst ? 0 : -1;
scope.matches.length = 0;
//transform labels
for(var i=0; i<matches.length; i++) {
locals[parserResult.itemName] = matches[i];
scope.matches.push({
id: getMatchId(i),
label: parserResult.viewMapper(scope, locals),
model: matches[i]
});
}
scope.query = inputValue;
//position pop-up with matches - we need to re-calculate its position each time we are opening a window
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
//due to other elements being rendered
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
scope.position.top = scope.position.top + element.prop('offsetHeight');
element.attr('aria-expanded', true);
} else {
resetMatches();
}
}
if (onCurrentRequest) {
isLoadingSetter(originalScope, false);
}
}, function(){
resetMatches();
isLoadingSetter(originalScope, false);
});
};
i just removed '&& hasFocus' this sipneet from the code
after ........
var getMatchesAsync = function(inputValue) {
var locals = {$viewValue: inputValue};
isLoadingSetter(originalScope, true);
$q.when(parserResult.source(originalScope, locals)).then(function(matches) {
//it might happen that several async queries were in progress if a user were typing fast
//but we are interested only in responses that correspond to the current view value
var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
if (onCurrentRequest) {
if (matches.length > 0) {
scope.activeIdx = focusFirst ? 0 : -1;
scope.matches.length = 0;
//transform labels
for(var i=0; i<matches.length; i++) {
locals[parserResult.itemName] = matches[i];
scope.matches.push({
id: getMatchId(i),
label: parserResult.viewMapper(scope, locals),
model: matches[i]
});
}
scope.query = inputValue;
//position pop-up with matches - we need to re-calculate its position each time we are opening a window
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
//due to other elements being rendered
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
scope.position.top = scope.position.top + element.prop('offsetHeight');
element.attr('aria-expanded', true);
} else {
resetMatches();
}
}
if (onCurrentRequest) {
isLoadingSetter(originalScope, false);
}
}, function(){
resetMatches();
isLoadingSetter(originalScope, false);
});
};

How to do queue of messages that shows in one div after delay?

How to implement queue which elements after shown with delay fadeOut and split out from array? This funcionallity should be provide message shows one after another in the same div even when showAlertBarMessages() is invoked many diffrent times like in FIFO. For now I can't clean shown elements. I spend one day and I don't know.
My current solution and working example: http://jsfiddle.net/ZtY38/:
var msgQueue = [];
var i = 1;
$('#add-msg').click(function () {
msgQueue.push("Message number " + i);
showAlertBarMessages();
i++;
});
function showAlertBarMessages() {
msgQueue.map(function (msg, idx) {
return function () {
var el = $('<div />').html(msg).addClass('msg').insertBefore('#msg-sequentially');
$(el).click(function () {
console.log("fadeOut and remove from queue");
});
if (idx > 0) {
return el.delay(2000).fadeIn(500).promise()
} else {
return el.fadeIn(500).promise()
}
};
}).reduce(function (cur, next) {
console.log("alredy shown fadeOut and remove from queue");
return cur.then(next);
}, $().promise());
}
HTML:
<div id="msg-sequentially"></div>
<button id="add-msg">Add next message</button>
Instead insertBefore should be append to #msg-sequentially but this doesn't work.
Or is there any completely other approach for this solution?
You could try that and see if it's fitting your needs:
DEMO
function showAlertBarMessages() {
var msg = msgQueue[0];
if (!$('#msg-sequentially').find(':visible').length) {
var el = $('<div />').html(msg).addClass('msg').appendTo('#msg-sequentially');
el.fadeIn(500).promise().done(function () {
$(this).delay(2000).fadeOut().promise().done(function () {
$(this).remove();
msgQueue.splice(0,1);
if(msgQueue.length) showAlertBarMessages();
});
});
}
}

Categories

Resources