I have a small SPA using angular-ui-bootstrap to provide the tabs component. The app mostly just displays data showing the operational status of an application, but one of the tabs has an input field that should get the focus when that tab is opened.
The controller for each tab component has a "tabOpened" and "tabClosed" function, which is called when that tab is opened or closed.
In the controller for the tab with the input field, I have the following:
$scope.tabOpened = function() {
$timeout(function() {
angular.element("handlerSearchInput").focus();
});
};
It's worth disputing whether it's reasonable to do this in a controller, as opposed to engineering some sort of directive to make the "focus()" call, but that's not the issue I need to solve first. My first problem is that this code doesn't actually work. I can see it hit the breakpoint in the function when I open the tab, but the field doesn't get the focus. There are no errors, it just doesn't work.
I've tested this in both Firefox and Chrome.
angular.element takes either string - in which case it will create a new element, or a jQuery selector which will return an existing element
so you should use angular.element("#handlerSearchInput").focus();
(API)
Related
Is it somehow possible to refocus an input field after a refresh which was last focused before the page was requested?
I have a Wicket Form within my WebPage and in this Form there are quite some input fields (like text fields) the user can use to filter my data view. But when the user for example has the focus on the second input field and then clicks on 'go to next page' within the data view he loses the focus, but due to accessibility it is necessary to refocus the second input field.
My idea was to first tag the input field with jQuery with "regain-focus" when focused:
$("input").focus(function() {
$("input").removeAttr("regain-focus");
$(this).attr("regain-focus", "regain-focus");
});
Then on server update search for the element with the "regain-focus" tag - but that's the part, I don't know how to do that... - tag the corresponding component with "autofocus":
input.add(AttributeModifier.append("autofocus", "autofocus"));
and refocus with javascript:
$('[autofocus]').focus();
Since you have JavaScript experience it would be much simpler to do it completely client side: $(document).on('focusin', 'input textarea', function(event) {localStorage.setItem('focus:'+location.pathname, event.target.id)}) and then use jQuery.ready() based logic to read the entry and use it.
When your page DOM/elements change between requests/refresh/ajax calls, it is better to use a CSS selector using optimal-select to store just a unique identifier for the element and use a JQuery selector to find it again for focus setting. I used this in the NoWicket web framework to remember the focused element on ajax calls. Example JS code here.
Currently I am working with protractor and Selenium web Driver.
I have the following problem:
I have a html page, and I make protractor clicking a button. Then a window pops up. This window contains a text box with the Name "Description":
<input type="Text" name="Description" ... />
Now when I try the following:
element(by.css('[name="Description"]')).sendKeys("rabbababab");
The browser does nothing, but protractor does not throw an error. No text is typed into the TextBox. Unfortunatelly, the name is the only way to identfy the input-TextBox.
What am I doing wrong?
Selecting directly by name works as well:
element(by.name('Description')).sendKeys("rabbababab");
OK guys, ive found the issue.
It wasnt an alert, its just a div, and all other controls are locked for user Input. but the Dialog covers a TextBox, wich has the same css-properties. So protractor just writes into the covered TextBox and i couldnt see it...
The Problem is solved
Sometimes if that element is inside iframe then you have to switch to that iframe. Just check that is there any iframe or modal available?
otherwise your code seems correct.
There is an inbuilt prompt handler in protractor where you can identify it and then send the data into the input field that you want. Here's how -
browser.Alert.sendKeys("rabbababab");
Note: The pop up window should have an input that it can accept some data into it else you command will fail.
If the above solution doesn't work then try sending data by switching to the pop-up and then sending text to it. Here's how -
browser.driver.switchTo().alert().sendKeys('rabbababab');
If at all there are many prompts, then you can use window handles function to switch to the one that you want. Here's how -
browser.getAllWindowHandles().then(function(handles){
browser.switchTo().window(handles[1]).then(function(){ //change the array index based on your pop-up's count
element(by.css('[name="Description"]')).sendKeys("rabbababab");
});
});
Hope it helps.
Maybe you have multiple objects which have name="Description" in your application.
You can find this in Chrome:
Right-click on the object
Click on Inspect element
Press CTRL+F
Type [name="Description"] and see how many results it finds.
element(by.css('[name="Description"]'))
is the same as
$('[name="Description"]')
If you find more than one, then you can try the following:
1. Try a click on the field before sending keys to it
2.
// This will search for the element of input with the name="Description" attribute
$('input[name="Description"]').sendKeys('rabbababab');
3.
You can try to put the following line, before sending keys to it :
browser.waitForAngular(); // wait until the angular app loads
Let us know how it worked.
Try using this,
$('input [name=Description]').sendKeys("rabbababab");
or
element(by.css('input [name=Description]')).sendKeys("rabbababab");
I want to be able to click inside a search box which is on the page and then click submit and have a couple expect statements.
So far I have this:
it('should redirect to the correct page', function(){
browser.driver.findElement(by.id('header-search')).click();
browser.driver.findElement(by.id('header-search')).sendKeys("aaa");
//element.all(by.id('header-search')).sendKeys("tfgm");
expect(browser.getCurrentUrl()).toEqual("http://localhost:8080/web/customer/account");
});
When I run protractor all it does is click on the box but does not paste in the text. Anyone have any ideas about what is going wrong?
There is no need to click the search field before entering keys, you can do that directly.
If the user is supposed to click a submit button after entering their search terms, don't forget to make protractor click it:
it('should redirect to the correct page', function(){
element(by.id('header-search')).sendKeys('foo');
$('[type="submit"]').click();
//Expect-statements
});
I would suggest taking a look at Elementor(Elementor Github Repo Here) to help you figure out what elements to call.
When you get it installed, there is a bug(Link to issue) that currently is active, however it will still find your elements for you(gives you the by.id/by.css/by.buttonText) for you to plug into your tests.
Keep in mind that when you start Elementor, it will open a NEW instance of Chrome. You will need to duplicate the chrome tab before using the Elementor plugin(right click the tab> Duplicate).
As for your tests, you shouldn't NEED to click the search element. .sendKeys() will essentially "click" that element. The way to think of how sendKeys() works is it finds the element you specify, then will plug in the keys you state into that element.
I would suggest trying to change your statement to be:
this.headerSearch = by.id('headerSearch'); //Or any by.something element
it('should redirect to the correct page', function() {
element(this.headerSearch).sendKeys("aaa\n"); // the \n will represent the "enter key"
});
You could go even further to parameterize the test and separate out your statements to follow the Page Object test methodology a bit better by doing:
This set of code will be in a PO file named something like SearchPage.js(remember the file needs to be exported):
this.headerSearch = by.id('headerSearch');
this.setHeaderSearch = function(search) {
element(this.headerSearch).sendKeys(search);
};
This will be in your main test(it will need to import your SearchPage.js page object file):
it('should do something like input keys into element', function(){
searchPO.setHeaderSearch('send some keys\n'); // the \n will represent the "enter key"
expect(browser.getCurrentUrl()).toEqual("http://localhost:8080/web/customer/account");
});
If you could provide everyone the HTML of the element your testing, we could help you out better.
I hope this was somewhat helpful to you!
Which browser are you using with protractor? If you are using Firefox, this should be an issue. sendKeyscannot work on Firefox browser.
I'm using jQuery UI autocomplete for data entry into an input field with the values being pulled from a database via ajax. That is all normal autocomplete.
However, the user can enter values that are not in the database and I wonder how to handle it.
I'm trying to avoid another ajax call to the database on change of the field to check if the data is new or not. Since I use autocomplete so often I would have to code many such checks.
If I know the data is new, I can give the user options whether to add it to the DB or it notify them of error input.
Maybe there's a notification from autocomplete that the user entered a new value.
Or maybe there's a way to restrict the user only to dropdown data. (that would cause other issues I think)
Or maybe somebody has a better idea.
Related questions (or maybe I should post these separately)
How do I trigger an autocomplete to open as soon as the user tabs into an empty field?
Setting the number of minLength to zero still requires the user to at least hit the down arrow.
Can I trigger the dropdown programmatically, such as from the image of a down arrow.
Thanks
Try the close event. (http://docs.jquery.com/UI/Autocomplete#event-close), the autocomplete closes if there is nothing found. You can probably look at the event to see what caused the close, and if it was an XHR it should mean that the autocomplete was closed caused by no items found. Can't guarantee it'll work, but it's probably worth a shot.
You can create a custom source function like this:
$("field").autocomplete({
source: function(request, response) {
fetchFromDB(request.term, function(data) {
// if data.length == 0 it was not in DB
response(data);
});
}
});
With fetchFromDB being whatever you are using now to get the results.
As for triggering autocomplete, you could do something like:
$("field").focus(function(event) {
var e = $.Event("keydown.autocomplete");
e.keyCode = $.ui.keyCode.DOWN;
$("field").trigger(e);
});
This should work, I used similar code to auto-trigger selection of the first element in autocomplete drop down.
Newbie question...
The objective:
I intend to have an HTML text input field as a kind of command line input.
An unordered HTML list shows the 5 most recent commands. Clicking on one of the last commands in this list should populate the command line input text field with the respective command (in order to re-execute or modify it).
An unordered HTML list contains a result set. Clicking on an ID in this list should bring the respective ID into the command line input text field.
In HTML (DHTML):
Works as expected: when clicking on the the link the command line input text field is populated with a recent command.
<li>here would be one of the recent commands</li>
In Javascript file:
Doesn't work as expected: when clicking on the the link the command-line-input-text-field gets populated with the respective value (as it should), BUT then it seems like the full HTML page is being reloaded, the text input field and all dynamically populated lists become empty.
function exec_cmd(cli_input_str) {
// a lot of code ...
// the code that should provide similar behavior as onclick=... in the DHTML example
$('.spa_id_href').click(function(){document.getElementById('cli_input').value = document.getElementById('cli_input').value + this.firstChild.nodeValue;});
}
Now the Question:
Besides a potential Javascript (syntax) error, what could cause the browser to reload the page?
In both cases, you do nothing to cancel the default function of clicking on a link.
In the plain HTML example, the link to the top of the page is followed.
You don't specify what the href attribute for the second example looks like, but whatever it is, it will be followed.
See http://icant.co.uk/articles/pragmatic-progressive-enhancement/ for a good explanation of event cancelling and good event design. See http://docs.jquery.com/Tutorials:How_jQuery_Works for some jQuery specific guidance.
Change
$('.spa_id_href').click(function(){...
to
$('.spa_id_href').click(function(evt){...//notice the evt param
and in the function, call
evt.preventDefault();
It seems that you just follow the link target URL. That is because you do not prevent the default click action:
e.preventDefault(); // `e` is the object passed to the event handler
// or
return false
Alternatively, you can set up a href starting with #, or not use <a> element at all (use <span style="cursor:pointer"> instead) β if itβs not a real link of course.
It's basically related to event cancelling...
Try this:
try { (
e || window.event).preventDefault();
}
catch( ex )
{
/* do Nothing */
}
While the other answers here make excellent points about canceling events, you will still run into problems if your JavaScript contains errors which prevent your event-canceling code from being run. (As might be the case if you're, say, debugging your code.
As an additional precaution, I strongly recommend you not use href="#" on links which only trigger scripts. Instead, use the void operator:
...
The reason for this is: when the event is not canceled, the browser will attempt to load the URL supplied by the href attribute. The javascript: "protocol" tells the browser to instead use the value of the accompanying code unless that value is undefined. The void operator exists explicitly to return undefined, so the browser stays on the existing page β with no reload/refresh β allowing you to continue debugging your script.
This also allows you to skip the entire event-canceling mess for JS-only links (though you will still need to cancel events in code attached to links which have a "fallback" URL for non-JS clients).