Struts2 jQuery autocompleter not working - autocomplete

Currently I am doing struts up-gradation task (struts2.0 to struts2.5). I want to replace struts dojo tag with struts-jquery.
Here I am facing some issue when replace struts-dojo autocompleter to struts-jQuery autocompleter.
Getting below response from server :
[
{
"firstName": "Bulwark Technologies LLC",
"partnerId": 925
},
{
"firstName": "Bulwark Technologies LLC1",
"partnerId": 926
},
{
"firstName": "Bulwark Technologies LLC2",
"partnerId": 927
}
]
For displaying at client side I am using Struts2-jquery-autocompleter -
<sj:autocompleter href="%{urlpartnerList}" list="%{partnerNameListBeanStruts2}" listValue="firstName" listKey="partnerId"/>
I am getting "undefined (multiple times - based on result found in query at server side)" in textbox.
Could some one please help here? Thanks in advance.

My suggestions in the comments lead you in the wrong direction, with this <sj:autocompleter/> it should work perfectly fine without changing it the server response. I messed up with the various options, that are available for this tag.
<sj:autocompleter href="%{jsonAction}" listKey="partnerId" listValue="firstName" name="firstname"/>
how can i get the value of the label element?
The trick with this autocompleter is, that the listValue is shown as selection in the visible text field but the listKey is used as value in a hidden field. And this hidden field will be used to send the value back to the server. That should also answer your question:
The <sj:autocompleter/> will create following html code:
<input type="hidden" name="firstname" value="HERE_IT_WILL_PUT_THE_LIST_KEY"/>
<input type="text" name="firstname_widget" value="HERE_IT_WILL_PUT_THE_LIST_VALUE"/>
Thus you only have to set the listKey tag with the list property name you want to have as a response.

Related

2019, Chrome 76, approach to autocomplete off

There are are few posts out there about this. You spend hours going through each answer, testing, reading comments, to find that there is no solution. What have you done in 2019, Chrome 76, that works?
Update, January 2020: It appears that as of Chrome 79, Autocomplete (as defined here) no longer treats autocomplete="some-unrecognised-value" as equal to autocomplete="on", so autocomplete="nope" or similar is now effective at disabling both Autocomplete and Autofill.
Update, April 2020: They changed it again. As of Chrome 81, autocomplete="some-unrecognised-value" is no longer effective at disabling the Autocomplete mechanism. However, Autofill now seems to be a lot more conservative than it was before - it still doesn't follow the spec (a field with name="email" and autocomplete="off" will still receive Autofill suggestions) but it doesn't offer up spurious address fragments on random form fields. My recommendation right now would therefore be to use autocomplete="off". If you want to do that on a field named email, you're probably out of luck though :-(
TL,DR: There appears to be no setting for the autocomplete attribute that will reliably turn off all autocomplete dropdowns. However, the circumstances that have led to this are quite convoluted and worth documenting, to hopefully clear up the masses of conflicting advice...
There are two distinct mechanisms present in current (76.0.3809.132) versions of Chrome, which we'll refer to as Autofill and Autocomplete (not necessarily their official names):
Autofill
The Autofill feature attempts to fill in forms using the address information stored in your browser settings. It can be identified by the "Manage addresses..." option (or similar) at the bottom of the dropdown. This feature does not honour autocomplete="off" or autocomplete="false", as a deliberate decision on the part of the Chrome developers.
In a statement outlining this decision, zkoch offered this workaround:
In cases where you really want to disable autofill, our suggestion at
this point is to utilize the autocomplete attribute to give valid,
semantic meaning to your fields. If we encounter an autocomplete
attribute that we don't recognize, we won't try and fill it.
As an example, if you have an address input field in your CRM tool
that you don't want Chrome to Autofill, you can give it semantic
meaning that makes sense relative to what you're asking for: e.g.
autocomplete="new-user-street-address". If Chrome encounters that, it
won't try and autofill the field.
This is the basis of attempted solutions such as autocomplete="nope"; the Autofill mechanism will skip any fields with autocomplete attribute values it doesn't recognise.
The code that implements this decision, for the record: https://chromium.googlesource.com/chromium/src/+/refs/tags/78.0.3903.1/components/autofill/core/browser/form_structure.cc#1218
Autocomplete
The Autocomplete feature provides a dropdown of previously-submitted values from this form field. This dropdown does not have a "Manage addresses..." option. Autocomplete does honour the autocomplete="off" or autocomplete="false" attribute; any other value (including 'invalid' ones such as autocomplete="nope") will leave it enabled.
Conclusion
Autocompletion dropdowns cannot be turned off through the autocomplete dropdown; any value that disables Autofill will leave Autocomplete enabled, and vice versa. Anyone who thinks they've found a working solution (either through autocomplete or some other method such as CSS hacks) should check that it works against both mechanisms.
Unfortunately it's probably going to be an uphill struggle to convince Chrome's developers that this is broken. The developers of Autofill apparently believe that they made a calculated decision to break autocomplete="off" while offering web developers an alternative; that alternative is broken, for more subtle reasons than they realise. From their perspective, the resulting howls of protest are coming from disgruntled developers too lazy to jump through one little hoop and update their autocomplete="off" attributes. In all the noise, the message isn't getting through: the hoop is broken.
Try using type="search" instead of "text" for your input field, I've done this several time and it works for me.
As of Dec 6, 2019, with Chrome v78.x
Standard methods like autocomplete="off" are now working almost fine for the latest versions of Chrome. Except for this one:
This thing is a real bummer because it doesn't only disrespect the standard/non-standard values like "nope" but there's literally no way to turn this off unless the input is not even remotely related with "addressy" terms.
How on earth we could possibly display address-related input fields without using address-related words? Here comes the easiest solution ever.
Make sure the input element's name and id don't include any address-related terms. Attributes like id="input-street" or name="destination-zip" are big no-no.
This is the most crucial part: If you are required to use any human-readable address terms for the text input or any of its adjacent elements, insert the "invisible" zero width joiner (‌) between the letters of the said term. In this way, we can fool the AI capability of Chrome and bypass its strict autocompletion behavior.
Some working examples:
<input id="input-stret" placeholder="S‌treet" autocomplete="off">
<form action="/action_page.php">
<label for="product-addres">Product A‌ddress</label>
<input name="addres" id="product-addres" autocomplete="off">
</form>
And there you go. No more pesky menus for managing addresses, nor any regular autocompletion menus.
As gasman's answer explains, both the autofill and autocomplete features must be disabled, which doesn't seem possible on a single input.
The only working solution I've found is to setting autocomplete="off" on the input and add hidden fake inputs before the real input that fool autofill, like so:
<input name="Fake_Username" id="Fake_Username" type="text" style="display:none">
<input name="Fake_Password" id="Fake_Password" type="password" style="display:none">
<input name="NameInput" id="NameInput" type="text" autocomplete="off">
* This answer is incorrect. I've published a better (but uglier) solution as a new answer and kept this answer since some parts may still be useful. If that's not how to deal with incorrect answers on stackoverflow, feel free to delete this one *
Consider using autocomplete=<nonce>, where <nonce> is unique per field and across page loads.
For example, if a field is the N-th field created after the page was requested at timestamp TS, its <nonce> can be chosen to be nope_<TS>_<N>.
Effect on autocomplete: since <nonce> is a custom value for autocomplete, chromium does not activate the autocomplete function (see form_structure.cc).
Effect on autofill: chromium recognizes a field by comparing its fingerprint with those of earlier encountered fields (see form_field_data.cc). If recognized it may offer a list of remembered values. The fingerprints contain the value of the autocomplete attribute. Since no two nonces are equal, no field is recognized.
Notes:
The terms autocomplete and autofill as used here are swapped compared to gasman's reply.
All fields should be created dynamically on the client-side (unless you are willing to not have the page cached).
Disabling autofill:
Set autocomplete attribute to a non-standard value, e.g. "nope".
Disabling autocomplete:
The autocomplete function stores field names and their values when a form is submitted.
There's (almost, see note 1) nothing sensible to be done to prevent storage except setting autocomplete to "off"/"false" (see why).
Unfortunately that's not an option as it would enable autofill.
However it's possible to prevent retrieval of previous values by appending "!<nonce>" to the field names, where <nonce> is unique per page load
(thus making field names unrecognizable).
On the client side this can be achieved by something like the following line of javascript (upon page load):
Array.prototype.slice.call(document.body.getElementsByTagName('INPUT'))
.forEach(function(elt) { elt.name += '!' + new Date().getTime(); });
On the server side the part (if any) starting at "!" should be dropped from variable names (upon receiving post variables).
PS: this answer is an erratum to my earlier solution which is cleaner but wasn't sufficiently tested and - as gasman rightly pointed out - doesn't work for ordinary forms. This new solution was tested on Chrome Canary 79, does work, has relatively small impact and degrades nicely. Still, I feel guilty about publishing this hack and will feel even more guilty if I ever encounter it in real forms. It is *very* dirty.
Note 1: the only way to prevent storage that does make sense is to not set the name attribute in the first place (or to unset it), which necessitates intercepting the submit event to post the data "manually" (using XMLHttpRequest). Since the question is about forms and this strategy bypasses the traditional form-mechanism I've not elaborated on that approach. It's a nicer solution though.
Addendum: I decided to follow up on note 1 since I really dislike having a non-localized solution. Here's a localized version in vanilla JS that limits all impact to a single spot on the client side. Append it as a script to the document body or put it in the onload handler of the document.
function disableInputSuggestions(form) { // note: code uses ECMA5 features
// tweak the inputs of form
var inputs = Array.prototype.slice.call(form.getElementsByTagName('INPUT'));
var nonce = Date.now();
inputs.forEach(function(input, i) {
input.autocomplete = 'nope'; // prevent autocomplete
input.originalName = input.name || input.id; // to not let this code break form handling of inputs without names (browsers fallback to the id in that case)
input.name = nonce + '_' + i; // prevent autofill (if you're willing to eliminate all input ids first, then clear the name instead)
});
// replace the default submit handler by a custom one
form.onsubmit = function(ev) {
// get the form data using the original variable names
var formData = new FormData();
inputs.forEach(function(input) { formData.set(input.originalName, input.value); });
// submit the form data using XMLHttpRequest (alternatively, use a helper form or temporarily undo the tweaks to form)
var submitter = new XMLHttpRequest();
submitter.open(form.getAttribute('method'), form.getAttribute('action'));
submitter.onreadystatechange = function() {
if(submitter.readyState == 4 && submitter.status == 200) {
// handle the server response, here assuming the default form.target = "_self"
document.open();
document.write(submitter.responseText);
document.close();
}
}
submitter.send(formData);
return false; // prevent submitting form
};
}
disableInputSuggestions(document.forms.myForm); // assumed: the form has id = myForm
In Chrome 91
You need to use a random value, meaning a value that will change each time you load the page.
From the tests that I did, chrome seems to remember any attribute value that it already encountered and will suggest the last seen value for that attribute value the next time. So, if you put autocomplete="nope", chrome will remember that autocomplete="nope" is equal to the last value that you put in autocomplete="nope".
By using a unique random value that chrome has never seen, it won't suggest anything because it has never seen that value.
PHP 7 Example
<input type="text" name="firstname" autocomplete="<?= bin2hex(random_bytes(10)) ?>" />
Limitations
It seems to work on address fields but it has no effect on login fields. I haven't tested with credit card fields.
Chrome version 81.
For me, when input type is TEL, EMAIL or SEARCH, it WORKS with autocomplete='disabled'.
When input type is NUMBER, it WORKS with autocomplete='off'.
But when input type is TEXT .. it may works with autocomplete='off'. If not, it will do with autocomplete='disabled'.
You can try this, perhaps it will work for you (it works in 95% of cases for me) :
// Désactivation de l'autocomplete des input text
function setAutocomplete(val) {
var E = document.getElementsByTagName('INPUT');
for (var i = 0 ; i < E.length ; i++) {
if (E[i].name == 'txt_nom') { console.log('txt_nom', E[i]); }
var type = E[i].type.toUpperCase();
if (E[i].autocomplete != '') { continue; }
if (type == 'HIDDEN') {
//
} else if (type == 'NUMBER') {
E[i].autocomplete = 'off';
} else if ((type == 'TEL') || (type == 'EMAIL') || (type == 'SEARCH')) {
E[i].autocomplete = 'disabled';
} else {
E[i].autocomplete = val;
}
}
}
// Exécution de diverses fonctions à la fin de chaque chargement
window.addEventListener("load", function() {
// Désactivation de l'autocomplete des input text
setAutocomplete('off');
});
try this, I used this little trick and it worked until now (September 2020). i hope this works for a lot of people
--HTML--
<input type="text" name="example" autocomplete="off">
--Javascript--
let elements = document.querySelectorAll('[autocomplete="off"]');
elements.forEach(element => {
element.setAttribute("readonly", "readonly");
element.style.backgroundColor = "inherit";
setTimeout(() => {
element.removeAttribute("readonly");
}, 500);
})
I made a small jQuery plugin that disables any type of autocomplete feature from any browser
It is made to be used on the form tag, it takes few parameters and can be nested with other jQuery methods.
$('#login_form').randomizeFormFields();
It transforms this:
<form id="login_form" action="" method="post">
<input type="text" name="email">
<input type="password" name="secret">
</form>
Into this:
<form id="login_form" action="" method="post">
<input type="text" name="yQoiFZkCrzwWXN3WWgM8Jblby">
<input type="password" name="ono1qamA9CzrH4tW2COoRtFKI">
</form>
It preserves the original names upon submit
// returned post (php example)
array(2) {
["email"]=>
string(16) "email#domain.com"
["secret"]=>
string(19) "supersecretpassword"
}
https://github.com/cicerogeorge/randomize-form-fields
Please fork it if you have ideas
I have tried with autocomplete = "off" and autocomplete = "nope" for EmailId textbox in html form but it is not working for Google Chrome. So I tried with below changes that worked for me.
<input type="email" class="tbx-input" name="Email" style="display:none;">
<input type="email" class="tbx-input" name="Email" id="Email" placeholder=" " required autocomplete="nope">
I couldnt get any of these suggestions to work... so I just made my input a textarea, made cols="1" and disabled adjusting the space.
<textarea style="resize: none;" type='search' class="form-control" rows="1" cols="50" .... >
No more suggestions
autocomplete='nope'
This is the current working solution for Chrome 76.

Capturing DOM Value using GTM

Total noob here so please bear with me:
I am trying to setup dynamic FB remarketing on a client ecommerce site.The problem is that the site doesn't have a data layer setup for this process so I'm trying to scrape some ecommerce values from the DOM (specifically the product name).
Essentially I am trying to capture the product name from this code string from the order confirmation page:
<h3> <p> **Icebreaker® Pocket Hat - Black/Cargo** </p> </h3>
The "Icebreaker® Pocket Hat - Black Cargo" is what I'm trying to feed into a custom FB pixel as a DOM variable in GTM. I've been experimenting all sorts of things but nothing has really worked so far. I've already captured order value this way so I'm fairly confident this is at least possible.
On the same order confirmation page, there is also this bit of JavaScript with the product name in it should that be of use as well:
<script type="text/javascript"> var gbTracker = new GbTracker('cabelasca', 'Production'); gbTracker.autoSetVisitor(); var visitorId = gbTracker.getVisitorId(); var sessionId = gbTracker.getSessionId(); gbTracker.sendOrderEvent({ cart: { items: [ { productId: '79530', title: '**Icebreaker® Pocket Hat - Black/Cargo**', price: 24.97, quantity: 1 }, ] } }); </script>
I am hoping someone knows how to pass this value using some kind of custom GTM variable. Any nudge towards an answer would be greatly appreciated. Thanks guys.
What I would normally do if I need to get some data from DOM is:
Create DOM element variable
This variable will find all necessary data from DOM. For example in your case variable should be like that:
CSS selector: h3 > p > a
Use this variable in your tags
Then in your tags just use this variable like that: {{Product Title}}

Allow HTML input tag and values on wysihtml5

I'm using wysihtml5 with bootstrap-wysihtml5 to save html templates (and at some point I need to load them on wysihtml5). I want to be able to allow the input tag on the editor.
The user workflow should be this:
Create a template with a "input=text" and a "input=checkbox" and save it.
Load the saved template on wysiwyg5 (it will show the inputs so the user can check the checkbox, input some value on the other, add some another HTML, etc)
Save all data again (including the input values/checked status)
In the Bootstrap-wysihtml5 parserRules I added:
"input": { check_attributes: { "type": "alt", "name":"alt","id":"alt", "value": "alt" }},
And this works fine to add (on HTML source view) <input/> elements but I cannot save the value the user insert on the inputs.
Any hints on how to accomplish this?
Edit 1:
Here is a fiddle showing the problem: http://jsfiddle.net/KuA9Z/1/
For me this works:
$('#id-of-textarea').val()
This returns:
<input type="text"> Some text.
If this does not work, can you provide a fiddle with your code?
I am using my own fork https://github.com/Waxolunist/bootstrap3-wysihtml5-bower/ with bootstrap3.

Grails - how to hide a date inside a form

I have an 'edit' view for a model that has several fields (one of which is a date). I only want a few of the fields visible to allow edits, so I just hide the other fields using <g:hiddenField>
But one of the fields is of type TimeStamp and I can't seem to find a way to hide this in the form. I tried
<g:form method="post" >
<g:textField name="firstName" value="${applicationUserInstance?.firstName}" />
<g:textField name="lastName" value="${applicationUserInstance?.lastName}" />
<g:datePicker name="createDate" style="visibility:hidden;" precision="day" value="${applicationUserInstance.createDate}" />
The date picker is still visible. Any idea how to hide the date so that I can just pass this to the update method upon submit of the form. Many thanks.
Just re-iterating Rob's comment here. No need to put that on the form. The only data you need on the form is the data you are updating and the ID of what is being updated. Everything else will just stay the same...
def update = {
def applicationUserInstance = User.get(param.id)
// at this point applicationUserInstance.createDate is
// correct.
applicationUserInstance.properties = params
// since no createDate was in the params, it doesn't change.
// so you're good
applicationUserInstance.save(flush:true)
}
Actually my answer below might not be the right answer to your question. Otherwise if you really just have a createdDate-field, which should keep track, when the entry was created in the database, I suggest you do it the Grails-way and use the reserved keywords 'dateCreated' and 'lastUpdated'
Check http://grails.org/doc/1.3.7/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.5.1 Events and Auto Timestamping
on how to use these. If you use these then my answer below will be helpful to control the visibility of these fields 'dateCreated', 'lastUpdated'
Suggestions for 'dateCreated', 'lastUpdated'
Probably you want this timestamp to be created automatically as you found it in the Grails documentation but you do not want it to be visible in your view.
Now, to exclude this timestamp from being visible, first
grails install-templates
I assume you have grails-1.3.7
Go to src/templates/scaffolding and check your gsp-files, e.g. 'create' and 'edit'
Search for this line:
<% excludedProps = ["version", "id",
and edit for example 'dateCreated'
<% excludedProps = ["dateCreated", "version", "id",
There is also a tutorial on this topic http://www.ibm.com/developerworks/java/library/j-grails01209/index.html
Greetings,
Jan

How do autocomplete suggestions work?

For example, if you type something in upper-right google/yahoo search box in firefox there will be some kind 'suggested auto complete' sort of thing.
Another example is in youtube search box and Stackoverflow tags edit box just below this question preview. How do they work? What technology behind 'em?
What technology behind 'em?
In case you are wondering which data structure is being used underneath then its called "trie" and for using less space compared to tries you can use "DAFSA"
How do they work?
both are implemented as a tree, where each node of tree corresponds to one character in a string and the character which appears before is parent of character which appears later e.g. The strings "tap", "taps", "top", and "tops" stored in a Trie (left) and a DAFSA (right),so as you begin to type tap..the tree is traversed based on the characters typed and shows the suggestions based on some weight assigned to each word, weight may be assigned based on usage frequency of the word.
Looking up string in worst case is O(m) time where m is the length of string.
Image is being referenced from the wikipedia articel : DAFSA,trie
That's done with the use of AJAX, this site has a nice tutorial on it:
AJAX Suggest Tutorial, and the WaybackMachine version, as website seems down.
A database with keywords and a bit of code is all there is to it as far as I know.
I'm learning how to use it right now actually, for work. :)
Another resource is w3schools. They have covered it as well.
They use JavaScript to normally:
Look at a local array of all possible values
Request another page (i.e. /autocomplete.php?q=partialText) in the background.
Call a webservice.
When the JavaScript has the list of entries to show it modifies the page to show the autocomplete box.
If you want to put an autocomplete box on your website I have used and found the following to be very good. It is also based on the popular jQuery framework.
jQuery autocomplete plugin
It's quite simple.
Client side:
Grab keystrokes in form field
On keystroke make an AJAX request to server
If another keystroke is entered immediately, cancel current AJAX request as it is obsolete now
Make a new AJAX requested with updated characters in form field
Show server response to client
Server side:
All words are already bucketed alphabetically
If client request comes in for "ove" find all words starting with ove, ordered by popularity
Return top matches to client
There's an excellent open-source Country selector in the Smashing Magazine article (link below) which includes a discussion of the usability challenges with plain autocomplete solutions, and fixes them.
While I'm UX, not Dev, I'm certain a clever developer could adapt this open-source code to handle other kinds of selections—not just the names of countries. :)
The article that describes the usability issues that this selector resolves.
The demo and open-source download. Try it!
Disclaimer: I have no connection to the folks who made this Country selector. I just happen to know about it, and I like to share information about Usability with developers, FWIW.
There's as many answers to this as there are different implementations of them. Our AutoCompleter which you can see a sample of in Stacked works by raising an event which then is handled in the codebehind of the .ASPX page from which you populate a ControlCollection with whatever controls you wish. We're however in Stacked only using Literal controls with Text content being anchor links. But we could add up checkboxes or images if we wanted to...
If you're on ASP.NET our AutoCompleter is a great place to start. If you're on "something else" then probably ScriptAculous AutoCompleter is another nice place to start...
i also have been recently working on autocomplete feature and we used lucene to index the text to be shown in autocomplete. Searching is fast with lucene. Somethings to look at when working with autocomplete data:
Freshness of suggestions,
Dependency on the long term data,
Regional dependency,
Language dependency
Update 2022
The marked answer is a little outdated. Suggestions autocomplete seems like magic on the surface but really what it is under the hood is
fast asynch communication and
searching through a list of keywords
Send a string to your database then return response in JSON to loop/iterate through. Then repeat as user types.
One good example is done with YELP Fusion.
Below is example with small library autocomplete.js
$(function () {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$(".sbx-custom__input").autocomplete({
source: availableTags
});
});
<!--jqueryui-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<!--autocompletejs-->
<script src="https://cdn.jsdelivr.net/npm/#tarekraafat/autocomplete.js#10.2.6/dist/autoComplete.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#tarekraafat/autocomplete.js#10.2.6/dist/css/autoComplete.min.css">
<!--input-->
<input class="sbx-custom__input" autocomplete="on" required="required" placeholder="autocomplete...">
here is the simple example from my code(using jquery + jquery ui). first i requested all data with ajax that i prefixed to inbox then i clicked one of them and so it redirects to another action succesfully.
$("#Name").autocomplete({
source: function (request, response) {
var prefix = { Name: request.term};
$.ajax({
url: '#Url.Action("FilterMastersByName", "JsonResult")',
data: JSON.stringify(prefix),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function (data) {
response($.map(data, function (item) {
return item;
}))
},
error: function (response) {
alert(response.responseText);
},
failure: function (response) {
alert(response.responseText);
}
});
},
select: function (e, i) {
var abc=i.item.val;
let a = document.createElement('a');
a.href = `/Home/GetMasterById?masterId=${abc}`;
a.click();
},
minLength: 1
});
});
Dont forget setFilterMastersByName action to httppost and GetMasterById to httpget
Here is one for MooTools.