I'm currently using the html5 autofocus for a login form. I am looking for a function that will autofocus the username textbox only if empty, and if not empty to autofocus on the next textbox.
With the HTML below
<input name="username" value="a" autofocus="autofocus">
<input name="password" type="password">
You can do something like this with jQuery
var $username = $('[name="username"]');
var $password = $('[name="password"]');
if($username.val().trim().length > 0){
$password.focus();
}
Should be that simple. Make sure Javascript is at the bottom of the page or you can use $(document).ready() function to make sure Javascript is run after HTML is rendered.
More details based on additional information
<asp:TextBox ID="UserName" runat="server" autofocus="true" required="true"></asp:TextBox>
The reason it doesn't work for your case is because you don't have an attribute called "name". I think you probably should read a little bit about jQuery selector to understand why. If you use ID, then this is how you would do it.
var $username = $('#UserName');
var $password = $('#password');
if($username.val().trim().length > 0){
$password.focus();
}
Of course you now have to match the selector for password so it will actually select password input to set the focus on.
Searches the page for input fields, and forces the focus on the first empty one. We might want to restrict the fields to a given form, and possibly add textareas as well - I'll leave that up yo you though - nothing too hard.
var inputs = document.getElementsByTagName('input'),
i = -1, I = inputs.length,
curr;
for (; ++i < I;) {
curr = inputs[i];
if ( !curr.value.length ) {
curr.focus();
break;
}
}
Related
I need a text field with the following behavior:
When the field is rendered, the current contents are hidden with password style (******), but if the user tries to edit it, the field gets cleared and they see on clear text what they are typing (so the behaviour is not entirely equivalent to PasswordTextField).
Any idea on how to achieve this behavior?
Thank you!
I think you should use some JavaScript to turn the field readable when focus event is fired. Here you can find a simple script that does the magic:
https://www.w3schools.com/howto/howto_js_toggle_password.asp
UPDATE:
In order to get the required behavior try the following code in the page above:
<!DOCTYPE html>
<html>
<body>
Password: <input type="password" value="FakePSW" id="myInput" onfocus="myFunction()"><br><br>
<script>
function myFunction() {
var x = document.getElementById("myInput");
x.value = "";
if (x.type === "password") {
x.type = "text";
} else {
x.type = "password";
}
}
<span id="continue" class="a-button a-button-span12 a-button-primary"><span class="a-button-inner"><input id="continue" tabindex="5" class="a-button-input" type="submit" aria-labelledby="continue-announce"><span id="continue-announce" class="a-button-text" aria-hidden="true">
Continue
</span></span></span>
Above the the HTML from part of a page, which has a 'Continue' button that i'm trying to click, using my script.
So, writing in Javascript, i'm trying to click this button. But nothing I have tried works.
My attempted answer is:
function() {
var goButton = document.getElementById("continue");
goButton.click();},
Why doesn't it work? Help me, please !
You have set the ID of both the span and the input field to "continue". ID's should be unique for a single element. When I enter your code in the browser's console it returns the following:
> var goButton = document.getElementById("continue");
< undefined
> goButton.valueOf()
< <span id="continue" class="a-button a-button-span12 a-button-primary">
You can see the span is the element being selected instead of the input submit button. You should rename either of the 2 elements so both have a unique ID and use that in your script.
Edit: OP mentioned the HTML can not be changed so instead of fixing the use of a not-unique ID this Javascript can be used:
function() {
var continueSpan = document.getElementById("continue");
var goButton = continueSpan.firstElementChild.firstElementChild;
goButton.click();}
I'm having a problem losing UI state changes after my observables change and was hoping for some suggestions.
First off, I'm polling my server for updates. Those messages are in my view model and the <ul> renders perfectly:
When my user clicks the "reply" or "assign to" buttons, I'm displaying a little form to perform those actions:
My problem at this point was that when my next polling call returned, the list re-binds and I lose the state of where the form should be open at. I went through adding view model properties for "currentQuestionID" so I could use a visible: binding and redisplay the form after binding.
Once that was complete, the form displays properly on the "current item" after rebinding but the form values are lost. That is to say, it rebinds, rebuilds the form elements, shows them, but any user input disappears (which of course makes sense since the HTML was just regenerated).
I attempted to follow the same pattern (using a value: binding to set the value and an event: {change: responseChanged} binding to update an observable with the values). The HTML fragment looks like this:
<form action="#" class="tb-reply-form" data-bind="visible: $root.showMenu($data, 'reply')">
<textarea id="tb-response" data-bind="value: $root.currentResponse, event: {keyup: $root.responseChanged}"></textarea>
<input type="button" id="tb-submitResponse" data-bind="click: $root.submitResponse, clickBubble: false" value="Send" />
</form>
<form action="#" class="tb-assign-form" data-bind="visible: $root.showMenu($data, 'assign')">
<select id="tb-assign" class="tb-assign" data-bind="value: $root.currentAssignee, options: $root.mediators, optionsText: 'full_name', optionsValue: 'access_token', optionsCaption: 'Select one...', event: {change: $root.assigneeChanged}">
</select>
<input type="button" id="tb-submitAssignment" data-bind="click: $root.submitAssignment, clickBubble: false" value="Assign"/>
</form>
Now, I end up with what seems like an infinite loop where setting the value causes change to happen, which in turn causes value... etc.
I thought "screw it" just move it out of the foreach... By moving the form outside of each <li> in the foreach: binding and doing a little DOM manipulation to move the form into the "current item", I figured I wouldn't lose user inputs.
replyForm.appendTo(theContainer).show();
It works up until the first poll return & rebind. Since the HTML is regenerated for the <ul>, the DOM no longer has my form and my attempt to grab it and do the .appendTo(container) does nothing. I suppose here, I might be able to copy the element into the active item instead of moving it?
So, this all seems like I'm missing something basic because someone has to have put a form into a foreach loop in knockout!
Does anybody have a strategy for maintaining form state inside a bound item in knockout?
Or, possibly, is there a way to make knockout NOT bind anything that's already bound and only generate "new" elements.
Finally, should I just scrap knockout for this and manually generate for "new items" myself when each polling call returns.
Just one last bit of info; if I set my polling interval to something like 30 seconds, all the bits "work" in that it submits, saves, rebinds, etc. I just need the form and it's contents to live through the rebinding.
Thanks a ton for any help!
Well, I figured it out on my own. And it's embarrassing.
Here is a partial bit of my VM code:
function TalkbackViewModel( id ) {
var self = this;
talkback.state.currentTalkbackId = "";
talkback.state.currentAction = "";
talkback.state.currentResponse = "";
talkback.state.currentAssignee = "";
self.talkbackQueue = ko.observableArray([]);
self.completeQueue = ko.observableArray([]);
self.mediators = ko.observableArray([]);
self.currentTalkbackId = ko.observable(talkback.state.currentTalkbackId);
self.currentAction = ko.observable(talkback.state.currentAction);
self.currentResponse = ko.observable(talkback.state.currentResponse);
self.currentAssignee = ko.observable(talkback.state.currentAssignee);
self.showActionForm = function(data, action) {
return ko.computed(function() {
var sameAction = (self.currentAction() == action);
var sameItem = (self.currentTalkbackId() == data.talkback_id());
return (sameAction && sameItem);
}, this);
};
self.replyToggle = function(model, event) {
// we're switching from one item to another. clear input values.
if (self.currentTalkbackId() != model.talkback_id() || self.currentAction() != "reply") {
self.currentResponse("");
self.currentAssignee("");
self.currentTalkbackId(model.talkback_id());
}
My first mistake was trying to treat the textarea & dropdown the same. I noticed the dropdown was saving value & reloading but stupidly tried to keep the code the same as the textarea and caused my own issue.
So...
First off, I went back to the using the $root view model properties for currentAssignee and currentResponse to store the values off and rebind using value: bindings on those controls.
Next, I needed to remove the event handlers:
event: { change: xxxChanged }
because they don't make sense (two way binding!!!!). The drop down value changes and updates automatically by using the value: binding.
The textarea ONLY updated on blur, causing me to think I needed onkeyup,onkeydown, etc. I got rid of those handlers because they were 1) wrong, 2) screwing up the value: binding creating an infinite loop.
I only needed this on the textarea to get up-to-date value updates to my viewmodel property:
valueUpdate: 'input'
At this point everything saves off & rebinds and I didn't lose my values but my caret position was incorrect in the textarea. I added a little code to handle that:
var item = element.find(".tb-assign");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
Some browsers behave OK if you just do item.focus().val(item.val()); but i needed to actually cause the value to "change" in my case to get the caret at the end so I saved the value, cleared it, then restored it. I did this in the event handler for when the event data is returned to the browser:
$(window).on("talkback.retrieved", function(event, talkback_queue, complete_queue) {
var open_mappings = ko.mapping.fromJS(talkback_queue);
self.talkbackQueue(open_mappings);
if (talkback_queue) self.queueLength(talkback_queue.length);
var completed_mappings = ko.mapping.fromJS(complete_queue);
self.completeQueue(completed_mappings);
if (self.currentTalkbackId()) {
var element = $("li[talkbackId='" + self.currentTalkbackId() + "']");
if (talkback.state.currentAction == "assign") {
var item = element.find(".tb-assign");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
} else {
var item = element.find(".tb-response");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
}
}
}
);
So, my final issue is that if I used my observables in my method "clearing" the values when a new "current item" is selected (replyToggle & assignToggle), they don't seem to work.
self.currentResponse("");
self.currentAssignee("");
I cannot get the values to clear. I had to do some hack-fu and added the line below that to just work around it for now:
$(".tb-assign").val("");
I have problem entering text in a text_field as when the script tries to enter anything in the field, it throws a popup. When manually entering, it does not throw a popup. The html of the text field is as below.
<input name="txtperc" type="text" value="0" maxlength="3" id="txtperc" tabindex="1" class="textBox valid" data-setfocus="true" onchange="return OnChangePercentAssignment('1','1');" onkeypress="return restrictKeyPress(event);" onpaste="cleanText.Wait(this)" style="width:30px;">
My code =
text_field(:percentage ,:id=>'txtperc')
self.percentage = 100
My guess is that the script tries to clear the text field and that is triggering the pop up to fire.
I also tried
text_field(:percentage ,:id=>'txtperc')
self.percentage = 10
browser.alert.ok
self.percentage = 100
Is there an alternate way to set/type into the text_field?
The application behaviour seems a bit strange. You might have to bypass the input element's event by executing javascript to set the field. This assumes that the event's being fired can be ignored.
You could define the page object as:
class MyPage
include PageObject
text_field(:percentage ,:id=>'txtperc')
def percentage=(value)
execute_script("document.getElementById('txtperc').value = '#{value}';")
end
end
And then input the field as normal:
self.percentage = 100
I've got an HTML5 form on my page with an email input that has place holder text in it. It works beautifully and I love the native validation!
I'm not sure how to serve old browsers best. I'm using a bit of javascript that copies the placeholder's text and imprints it as a value. It works well, but then the form validation goes off because there's text that isn't an email address in the form.
I do not want to lose the validation.. Any ideas?
HTML
<input id="email" type="email" placeholder="Enter your email address">
JavaScript (Prototype):
var Placeholder = Class.create({
initialize: function (element) {
this.element = element;
this.placeholder = element.readAttribute('placeholder');
this.blur();
Event.observe(this.element, 'focus', this.focus.bindAsEventListener(this));
Event.observe(this.element, 'blur', this.blur.bindAsEventListener(this));
},
focus: function () {
if (this.element.hasClassName('placeholder'))
this.element.clear().removeClassName('placeholder');
},
blur: function () {
if (this.element.value === '')
this.element.addClassName('placeholder').value = this.placeholder;
}
});
Event.observe(window, 'load', function(e){
new Placeholder($('email'));
});
EDIT:
Wouldn't it be great if browsers supporting placeholder ignored the value attribute?
EDIT 2:
No, I don't want to set the input type to text. That will change the validation's behavior from email syntax to spellcheck.
User Modernizr to detect support for placeholder and only use your javascript to copy the placeholder text if support doesn't exist:
if(!Modernizr.input.placeholder){
// copy placeholder text to input
}
This will prevent it from doing the copy on browsers supporting html5 form attributes like placeholder.
Try this:
<input type="email" value="Enter Email"
onfocus="if (this.value == 'Enter Email') {this.value = '';}"
onblur="if (this.value =='') {this.value = 'Enter Email';}" />
I know it's an old question, but it could help other users that come across this question.
You can use this http://afarkas.github.com/webshim/demos/demos/webforms.html for form validation with support for older browsers. It sits on top of jQuery and Modernizer and is pretty easy to implement.
Hope it helps.