Failed: element not visible (Protractor AngularJS) - html

Apparently Protractor cannot find this element in a menu on my application, elements above are ok. My code is:
this.openMenu("toogleMenuButton")
let prodLink = element(by.id("menu12"));
if (prodLink.isPresent()) {
prodLink.click();
browser.sleep(500);
} else {
return false;
}
The HTML code is:
<a _ngcontent-c13=""
appaccordiontoggle=""
class="relative mat-ripple"
md-ripple=""
routerlinkactive="open"
style="margin-left: 47px"
ng-reflect-class-base="relative"
ng-reflect-router-link-active="open"
id="menu12">
<span _ngcontent-c13="">Produtos</span>
</a>
Could someone help me please?

You need code to wait element to be visible (present in DOM and also visible - have height and width greater that 0). I put wait of 30s:
var EC = protractor.ExpectedConditions;
var prodlink = element(by.id('menu12'));
browser.wait(EC.visibilityOf(element(by.id('menu12'))), 30000, "prod link element is not visible").then(function() {
prodlink.click();
}

Analysis:
Your code has wrong at
if (prodLink.isPresent())
As we know all Protractor APIs are Async and return promise. When Javascript Enginee executing this line, Javascript get a promise object not a boolean value, Actually this IF statement will always true, because promise object not null, and it's very possible protractor have not to detect the link present from page, because all communication with page are Async.
Solution:
The correct code as below:
this.openMenu("toogleMenuButton")
let prodLink = element(by.id("menu12"));
prodLink.isPresent().then(function(present){
if(present) {
prodLink.click();
return true;
}
return false;
});
My code just to point out your mistake, the correct way in coding to click the link should be as 'Sanja Paskova' way.

Related

How to send a single request through p:commandButton inside p:dialog? [duplicate]

I have following jQuery code to prevent double clicking a button. It works fine. I am using Page_ClientValidate() to ensure that the double click is prevented only if the page is valid. [If there are validation errors the flag should not be set as there is no postback to server started]
Is there a better method to prevent the second click on the button before the page loads back?
Can we set the flag isOperationInProgress = yesIndicator only if the page is causing a postback to server? Is there a suitable event for it that will be called before the user can click on the button for the second time?
Note: I am looking for a solution that won't require any new API
Note: This question is not a duplicate. Here I am trying to avoid the use of Page_ClientValidate(). Also I am looking for an event where I can move the code so that I need not use Page_ClientValidate()
Note: No ajax involved in my scenario. The ASP.Net form will be submitted to server synchronously. The button click event in javascript is only for preventing double click. The form submission is synchronous using ASP.Net.
Present Code
$(document).ready(function () {
var noIndicator = 'No';
var yesIndicator = 'Yes';
var isOperationInProgress = 'No';
$('.applicationButton').click(function (e) {
// Prevent button from double click
var isPageValid = Page_ClientValidate();
if (isPageValid) {
if (isOperationInProgress == noIndicator) {
isOperationInProgress = yesIndicator;
} else {
e.preventDefault();
}
}
});
});
References:
Validator causes improper behavior for double click check
Whether to use Page_IsValid or Page_ClientValidate() (for Client Side Events)
Note by #Peter Ivan in the above references:
calling Page_ClientValidate() repeatedly may cause the page to be too obtrusive (multiple alerts etc.).
I found this solution that is simple and worked for me:
<form ...>
<input ...>
<button ... onclick="this.disabled=true;this.value='Submitting...'; this.form.submit();">
</form>
This solution was found in:
Original solution
JS provides an easy solution by using the event properties:
$('selector').click(function(event) {
if(!event.detail || event.detail == 1){//activate on first click only to avoid hiding again on multiple clicks
// code here. // It will execute only once on multiple clicks
}
});
disable the button on click, enable it after the operation completes
$(document).ready(function () {
$("#btn").on("click", function() {
$(this).attr("disabled", "disabled");
doWork(); //this method contains your logic
});
});
function doWork() {
alert("doing work");
//actually this function will do something and when processing is done the button is enabled by removing the 'disabled' attribute
//I use setTimeout so you can see the button can only be clicked once, and can't be clicked again while work is being done
setTimeout('$("#btn").removeAttr("disabled")', 1500);
}
working example
I modified the solution by #Kalyani and so far it's been working beautifully!
$('selector').click(function(event) {
if(!event.detail || event.detail == 1){ return true; }
else { return false; }
});
Disable pointer events in the first line of your callback, and then resume them on the last line.
element.on('click', function() {
element.css('pointer-events', 'none');
//do all of your stuff
element.css('pointer-events', 'auto');
};
After hours of searching i fixed it in this way:
old_timestamp = null;
$('#productivity_table').on('click', function(event) {
// code executed at first load
// not working if you press too many clicks, it waits 1 second
if(old_timestamp == null || old_timestamp + 1000 < event.timeStamp)
{
// write the code / slide / fade / whatever
old_timestamp = event.timeStamp;
}
});
you can use jQuery's [one][1] :
.one( events [, data ], handler ) Returns: jQuery
Description: Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
see examples:
using jQuery: https://codepen.io/loicjaouen/pen/RwweLVx
// add an even listener that will run only once
$("#click_here_button").one("click", once_callback);
using count,
clickcount++;
if (clickcount == 1) {}
After coming back again clickcount set to zero.
May be this will help and give the desired functionality :
$('#disable').on('click', function(){
$('#disable').attr("disabled", true);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="disable">Disable Me!</button>
<p>Hello</p>
We can use on and off click for preventing Multiple clicks. i tried it to my application and it's working as expected.
$(document).ready(function () {
$("#disable").on('click', function () {
$(this).off('click');
// enter code here
});
})
This should work for you:
$(document).ready(function () {
$('.applicationButton').click(function (e) {
var btn = $(this),
isPageValid = Page_ClientValidate(); // cache state of page validation
if (!isPageValid) {
// page isn't valid, block form submission
e.preventDefault();
}
// disable the button only if the page is valid.
// when the postback returns, the button will be re-enabled by default
btn.prop('disabled', isPageValid);
return isPageValid;
});
});
Please note that you should also take steps server-side to prevent double-posts as not every visitor to your site will be polite enough to visit it with a browser (let alone a JavaScript-enabled browser).
The absolute best way I've found is to immediately disable the button when clicked:
$('#myButton').click(function() {
$('#myButton').prop('disabled', true);
});
And re-enable it when needed, for example:
validation failed
error while processing the form data by the server, then after an error response using jQuery
Another way to avoid a quick double-click is to use the native JavaScript function ondblclick, but in this case it doesn't work if the submit form works through jQuery.
One way you do this is set a counter and if number exceeds the certain number return false.
easy as this.
var mybutton_counter=0;
$("#mybutton").on('click', function(e){
if (mybutton_counter>0){return false;} //you can set the number to any
//your call
mybutton_counter++; //incremental
});
make sure, if statement is on top of your call.
If you are doing a full round-trip post-back, you can just make the button disappear. If there are validation errors, the button will be visible again upon reload of the page.
First set add a style to your button:
<h:commandButton id="SaveBtn" value="Save"
styleClass="hideOnClick"
actionListener="#{someBean.saveAction()}"/>
Then make it hide when clicked.
$(document).ready(function() {
$(".hideOnClick").click(function(e) {
$(e.toElement).hide();
});
});
Just copy paste this code in your script and edit #button1 with your button id and it will resolve your issue.
<script type="text/javascript">
$(document).ready(function(){
$("#button1").submit(function() {
$(this).submit(function() {
return false;
});
return true;
});
});
</script
Plain JavaScript:
Set an attribute to the element being interacted
Remove the attribute after a timeout
If the element has the attribute, do nothing
const throttleInput = document.querySelector('button');
throttleInput.onclick = function() {
if (!throttleInput.hasAttribute('data-prevent-double-click')) {
throttleInput.setAttribute('data-prevent-double-click', true);
throttleInput.setAttribute('disabled', true);
document.body.append("Foo!");
}
setTimeout(function() {
throttleInput.removeAttribute('disabled');
throttleInput.removeAttribute('data-prevent-double-click');
}, 3000);
}
<button>Click to add "Foo"!</button>
We also set the button to .disabled=true. I added the HTML Command input with type hidden to identify if the transaction has been added by the Computer Server to the Database.
Example HTML and PHP Commands:
<button onclick="myAddFunction(<?php echo $value['patient_id'];?>)" id="addButtonId">ADD</button>
<input type="hidden" id="hasPatientInListParam" value="<?php echo $hasPatientInListParamValue;?>">
Example Javascript Command:
function myAddFunction(patientId) {
document.getElementById("addButtonId").disabled=true;
var hasPatientInList = document.getElementById("hasPatientInListParam").value;
if (hasPatientInList) {
alert("Only one (1) patient in each List.");
return;
}
window.location.href = "webAddress/addTransaction/"+patientId; //reloads page
}
After reloading the page, the computer auto-sets the button to .disabled=false. At present, these actions prevent the multiple clicks problem in our case.
I hope these help you too.
Thank you.
One way I found that works is using bootstrap css to display a modal window with a spinner on it. This way nothing in the background can be clicked. Just need to make sure that you hide the modal window again after your long process completes.
so I found a simple solution, hope this helps.
all I had to do was create a counter = 0, and make the function that runs when clicked only runnable if the counter is = 0, when someone clicks the function the first line in the function sets counter = 1 and this will prevent the user from running the function multiple times when the function is done the last line of the code inside the function sets counter to 0 again
you could use a structure like this, it will execute just once:
document.getElementById('buttonID').addEventListener('click', () => {
...Do things...
},{once:true});

Polymer blocking keyboard input?

I inherited an Adobe CEP extension at work. Trying to wrap my head around an issue that makes it so absolutely no input from keyboard works on text inputs. To elaborate, absolutely no keyboard input works in Polymer's text inputs. The input get's focused, but if I type anything in them I get the mac error alert sound. The only key that I was able to make work was "tab". Anything else does not work. It's built using Polymer. At first I was unsure what's causing the issue, and since I inherited this project I was confused where to start. After about a day of debugging, I believe it's related to Polymer somehow. The reason for this is, if I remove the Polymer HTML element that renders it, and just put an input there, the input works. It only seems to block input inside the <template> ... </template>. I've looked all over the internet for any clues on what could be causing Polymer to block this input, there's no errors in console or anything, and I've come up short handed.
Does anyone have any insight on this?
I'm facing the same problem. Actually, it is not related to polymer, but to the webcomponents polyfill. If you try the following source code inside an Adobe CEP extension, you will see that you can click inside both the elements, select any text, but you are not able to edit it.
<html>
<head>
<script>
// Force all polyfills on
if (window.customElements) window.customElements.forcePolyfill = true;
ShadyDOM = {
force: true
};
ShadyCSS = {
shimcssproperties: true
};
</script>
<script src="node_modules/#webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
<template id="x-foo-from-template">
<input value="from template">
</template>
<script>
let tmpl = document.querySelector('#x-foo-from-template');
customElements.define('x-foo-from-template', class extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({
mode: 'open'
});
shadowRoot.appendChild(tmpl.content.cloneNode(true));
}
});
customElements.define('x-foo-from-dynamic', class extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({
mode: 'open'
});
var inputEl = document.createElement('input');
inputEl.value = "from created element";
shadowRoot.appendChild(inputEl);
}
});
</script>
<x-foo-from-template></x-foo-from-template>
<x-foo-from-dynamic></x-foo-from-dynamic>
</body>
</html>
Faced with the same issue, we finally found documented that Adobe will hand over all keypresses to the host application unless it can determine that an input or dropdown element has focus. I expect this is done using a simple check on document.activeElement. When the Shadow DOM is involved, Adobe would have to do something like
let target = document.activeElement;
while (target.shadowRoot && target.shadowRoot.activeElement) {
target = target.shadowRoot.activeElement;
}
in order to find the underlying <input> element.
Since this is currently not working, we needed to use registerKeyEventsInterest to explicitly have all keypresses be processed by our code.
var csInterface = new CSInterface();
var keyEvents = [];
// All the keyCodes you need, with the modifiers used
keyEvents.push({ keyCode: 0 });
keyEvents.push({ keyCode: 0, metaKey: true });
// ...
csInterface.registerKeyEventsInterest(JSON.stringify(keyEvents));
We actually went ahead and looped 0..255 and registered for all modifiers. With the exception of keyboard based copy-paste, we now have full functionality with our webcomponents (mostly PolymerElement/LitElement based).
https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#register-an-interest-in-specific-key-events

How to disable double click on img tag

I have one delete img and on clicking on that it will make an api call and delete the record, but on double click it is making multiple api calls. I tried disabling double click using ng-dblclick="return false;" but no use. can some one help me How to disable double click on img tag using angular js?
PS: I have seen this approach is working on div tag
Thanks
Here's an example of how you could avoid multiple api calls. It may look different than your code, but since you havn't provided any, this is the best I can do.
In your controller you'd have a variable, that you set to true on the first click and set to false when your API call returns with a response. Each time the function making the API call is executed, you check whether this variable is true. If it is, you simply return before making the API call again. This is the code (I'm skipping best practices here, to keep the sample minimal):
angular.module('app').controller('myController', function($http){
var ctrl = this;
ctrl.isDeleting = false;
ctrl.deleteRecord = function(id){
if(ctrl.isDeleting){
return;
}
ctrl.isDeleting = true;
$http.delete('[your_api_url]/' + id).finally(function(){
ctrl.isDeleting = false;
});
};
});
Then your html would look like this:
<img src="images/delete.png" ng-click="$ctrl.deleteRecord(id)" ng-class="{'img-disabled': $ctrl.isDeleting}" />
and add some css for visual feedback to the user:
.img-disabled {
cursor: default;
opacity: 0.5;
}
That's it.
To reiterate, I have no idea how your code looks, so I've taken a few assumptions that you'll have to account for when applying this solution.
The easiest option would be :
<img src="Tulips.png" alt="Add" height="25" width="25" ng-disabled="!isEnabled" ng-click="!isEnabled"></img>
var app = angular.module('main', []).
controller('DemoCtrl', function($scope, $filter) {
$scope.isEnabled=true;
});

Angular 4 Execute Function when html fully loaded

I have a problem with asynchronous HTTP calls in Angular 4 using typescript/components... I create an array of objects, and in the HTML I have checkboxes next to the objects. Now I want certain objects to be checked, by executing a function in angular. However when I do
(document.getElementById(id) as HTMLInputElement).checked = true;
In my component.ts.
It can't find the element however when I do the same code in a function that executes when you push a button it works. So the problem is that the HTML is not fully loaded when I execute the function. How can I make sure the HTML is fully loaded?
Yeah You shouldn't be manipulating the DOM.
Tag your HTML element in the html using hash.
<input ... #inputname />
Retrieved in the ts controller component.
#ViewChild('inputname') theinput;
Check after view init. ngAfterViewInit if it is checked
ngAfterViewInit() {
...
(this.form as HTMLInputElement).checked
...
}
Consider this as the last option since I wouldn't recommend direct DOM manipulation in Angular. But if you are still facing the issue, use can use my solution as a work around.
In constructor ,
let interval = setInterval(() => {
let flag = self.checkFunction();
if (flag)
clearInterval(interval);
}, 100)
Now create the function
checkFunction() {
if(document.getElementById(id)){
(document.getElementById(id) as HTMLInputElement).checked = true;
return true;
}
return false;
}

Jasmine test is not detecting that button has been clicked

I have written a Jasmine test that clicks on the first error message in a list and closes it. It then checks that the number of errors has reduced to the expected amount:
it('should close the error if the errors close button is clicked', function() {
element.all(by.repeater('error in errorList')).then(function(errorList) {
errorList[0].element(by.id('error0')).then(function(error0) {
error0.click();
var arrayLength = errorList.length;
expect(arrayLength).toEqual(1);
});
});
});
When I run this I get the message Expected 2 to equal 1. 2 is the length of the error array at the start of the test. If I manually recreate this, the error message definitely closes when clicking anywhere within error0. Is it possible that clicking this takes some time and this isn't registered by the time the expect statement is run?
Here is the relevant part of the HTML:
<a class="po-cross-link" href="" ng-click="closeError(error)" id="{{'error'+$index}}">
<img class="po-cross" src="\assets\black-cross.png" alt="close">
</a>
Thanks
I guess you are changing the model in the click handler but you expect the DOM elements to be changed instantly. Angular needs a $digest cycle to update the DOM according to the model, so I suggest you run scope.$digest() after clicking. If you don't have a scope in your test, you can also use the $rootScope.
Thanks...I sussed it shortly after posting. Similar in principle the other answer given I think. It's because I needed to get the most recent version of the DOM. I added in a second asynchronous function as follows:
it('should close the error if the errors close button is clicked', function() {
element.all(by.repeater('error in errorList')).then(function(errorList) {
errorList[0].element(by.id('error0')).then(function(error0) {
error0.click();
element.all(by.repeater('error in errorList')).then(function(errorListNew) {
var arrayLength = errorListNew.length;
expect(arrayLength).toEqual(1);
});
});
});
});