After having a few small wins with JS (still very much a learner) I have now inherited a task which is to change a reductive search of sorts.
Users now want to have the search work from a submit button, instead of a keyup after 3rd character. I have completed submit forms before where the form would post, but I have never come across something as complex as this before.
I have had a look through the large JS file, and located the search function which contains the keyup function.
F.initSearch = function(opts){
if(!opts || !opts.ele){
return;
}
if(!opts.start_length){
this.opts.search.start_length = 2
}
this.$search_ele = $(this.opts.search.ele);
if(this.$search_ele.length){
this.has_search = true;
this.searchFn = this.buildSearchFn(opts.fields);
this.bindEvent(opts.ele, 'keyup');
}
};
However, I am having difficulty with changing over from keyup to button click.
This is what I have done:
I have updated the form to include the button
<form>
<div class="searchBox">
<input type="text" id="search" class="search__text-input" placeholder="Search"/>
</div>
<div class="formBox">
<button id="searchbtn">Search</button>
</div>
</form>
I have tried to update the script with some jquery which follows the same pattern
$( "#searchbtn" ).this.bindEvent(opts.ele, 'click');
Lastly, I have attempted to then update the existing - which is now leaving me somewhat defeated:
F.initSearch = function(opts) {
if(!opts || !opts.ele) {
return;
}
if(!opts.start_length) {
this.opts.search.start_length = 2
}
this.$search_ele = $(this.opts.search.ele);
if(this.$search_ele.length) {
this.has_search = true;
this.searchFn = this.buildSearchFn(opts.fields);
// this.bindEvent(opts.ele, 'keyup');
/* Trying to swap keyup for button click */
$( "#searchbtn" ).this.bindEvent(opts.ele, 'click');
}
};
Link to JSFiddle: https://jsfiddle.net/mcmacca002/bo0y3u7p/2/
Clearly I am approaching this wrong, and some guidance would be greatly appreciated.
Related
Im building a new personal blog and I'm using ajax to post back to a C# Controller to get the results for pagination.
Page 2 loads with the results however, none of the javascript is reloaded because, I believe, when I partially reload the pagination part of the page, it destroys everything in the DOM and because the full page doesn't reload, the javascript isn't invoked.
So I'm looking for a bit of help on working out how to get the external javascript to run again. What it does is adds css classes, gives some fade effects etc.
success: function (data) {
if (data != null) {
var page = data
$('#blogsContainer').empty();
$('#blogsContainer').replaceWith(page);
So the success works, I clear out the blogsContainer with the new data.
I'm guessing I need to add a function after the replace to then apply everything that is in an external main.js file.
The main.js file looks like this
(function($) {
var contentWayPoint = function() {
var i = 0;
$('.ftco-animate').waypoint( function( direction ) {
if( direction === 'down' && !$(this.element).hasClass('ftco-animated') ) {
i++;
$(this.element).addClass('item-animate');
setTimeout(function(){
$('body .ftco-animate.item-animate').each(function(k){
var el = $(this);
setTimeout( function () {
var effect = el.data('animate-effect');
if ( effect === 'fadeIn') {
el.addClass('fadeIn ftco-animated');
} else if ( effect === 'fadeInLeft') {
el.addClass('fadeInLeft ftco-animated');
} else if ( effect === 'fadeInRight') {
el.addClass('fadeInRight ftco-animated');
} else {
el.addClass('fadeInUp ftco-animated');
}
el.removeClass('item-animate');
}, k * 50, 'easeInOutExpo' );
});
}, 100);
}
} , { offset: '95%' } );
};
contentWayPoint();
}
The first page has the following applied to it on page load:
<div class="col-md-4 d-flex ftco-animate fadeInUp ftco-animated">
<div class="blog-entry justify-content-end">
...
</div>
</div>
But as you can see, when I press page 2, the div is missing some key css
<div class="col-md-4 d-flex ftco-animate">
<div class="blog-entry justify-content-end">
</div>
</div>
How would I apply the missing css after the partial reload with ajax?
I hope this is clear what I am trying to do but if not, please just ask.
I think the solution may be to re-execute the contentWayPoint() function at the end of the success callback. However, its likely out of scope by then. There are two simple ways to ensure its not :
The cleanest would be to ensure that the code that sets up your pagination is inside the same (function($) {}) block in main.js - that way it will "capture" the function.
The other, dirtier way, would be to change var contentWaypoint= function... to window.contentWaypoint = function - then use window.contentWaypoint() whenever you need to invoke it. THere are much better ways to doing this, but that might get you going.
I have a problem that i can't fix.
Keyboard doesn't show on input.focus() on IOS
searchMobileToggle.addEventListener('click', function() {
setTimeout(function(){
searchField.focus();
}, 300);
});
I've been looking for a solution with no result, i know this is a frequently unsolved question but i see NIKE (https://m.nike.com/fr/fr_fr/) and FOODSPRING (https://www.foodspring.fr/) doing it on mobile.
So i'm wondering how do they do ?
None of the other answers worked for me. I ended up looking into the Nike javascript code and this is what I came up with as a reusable function:
function focusAndOpenKeyboard(el, timeout) {
if(!timeout) {
timeout = 100;
}
if(el) {
// Align temp input element approximately where the input element is
// so the cursor doesn't jump around
var __tempEl__ = document.createElement('input');
__tempEl__.style.position = 'absolute';
__tempEl__.style.top = (el.offsetTop + 7) + 'px';
__tempEl__.style.left = el.offsetLeft + 'px';
__tempEl__.style.height = 0;
__tempEl__.style.opacity = 0;
// Put this temp element as a child of the page <body> and focus on it
document.body.appendChild(__tempEl__);
__tempEl__.focus();
// The keyboard is open. Now do a delayed focus on the target element
setTimeout(function() {
el.focus();
el.click();
// Remove the temp element
document.body.removeChild(__tempEl__);
}, timeout);
}
}
// Usage example
var myElement = document.getElementById('my-element');
var modalFadeInDuration = 300;
focusAndOpenKeyboard(myElement, modalFadeInDuration); // or without the second argument
Note that this is definitely a hacky solution, but the fact that Apple hasn't fixed this in so long justifies it.
I found a solution, click() didn't work, but i figured it out.
searchMobileToggle.addEventListener('click', function() {
if(mobileSearchblock.classList.contains('active')) {
searchField.setAttribute('autofocus', 'autofocus');
searchField.focus();
}
else {
searchField.removeAttribute('autofocus');
}
});
I was working with vue.js that was removing input autofocus attribute, when the component was loaded.
So i had it on click, but there was another problem, the autofocus only worked once, but combined with focus(), it now work all the time :)
Thanks for your help !
This really drives me/us crazy. It works fine on the Android phone, but something is disabled by the Apple developer. (I understand it's annoying to pop the keyboard when not necessary though).
I accidentally found out that the "popup" module from Semantic-UI fixes this magically.
Note that the solution works for SemanticUI (#semantic-ui team may tell what event makes this work)
Here are how I did:
const [search, setSearch] = useState(false);
const inputRef = useRef(null);
React.useEffect(() => {
if (search) {
inputRef.current.focus();
} else {
inputRef.current.blur();
}
}, [search]);
<div onClick={() => setSearch(true)}>
<Popup
content="Search for Swimmers and Time Standards."
offset={[-500, -1000]}
trigger={<Icon name="search" />}
/>
</div>
{search && <Input ref={inputRef} />}
As you see, I wrapped the trigger Icon with the Popup module, and hide the Popup content by setting the crazy offset. And then it magically works.
See the demo here: https://swimstandards.com/ (check it out on your iPhone)
Angular solution:
on button click we need to create temporary input, append to existing container (close to our input) and focus on it.
btnClicked() {
this.showModal = true;
this.searchBar = this.renderer2.selectRootElement('#searchBar', true);
// 2nd argument preserves existing content
// setting helper field and focusing on it
this.inputHelper = this.renderer2.createElement('input');
this.renderer2.appendChild(this.searchBar, this.inputHelper);
this.inputHelper.focus();
let event = new KeyboardEvent('touchstart',{'bubbles':true});
this.searchBarButton.nativeElement.dispatchEvent(event);
}
after modal/target input is shown, we move focus and remove temporary one:
initiateKeyboard() {
setTimeout(()=> {
this.searchBarInput.nativeElement.focus();
this.renderer2.removeChild(this.searchBar, this.inputHelper);
},180);
}
and template:
<div id="searchBar">
<input type="button" class="button is-link is-light" value="Search" (click)="btnClicked()" (touchstart)="initiateKeyboard()" #searchBarButton>
</div>
You just need to remember that iPhone may zoom screen, so you need to adjust parameters of temporary input.
working solution: https://inputfocus.vercel.app/
Worked in 2022 with ios 16!
OMG, I searched for so long and the above solution won't work for me.
Here is how it worked for me. I wrapped the input in a React FocusLock component. Check this package out: https://www.npmjs.com/package/react-focus-lock
Here is a small example:
<FocusLock>
<Input />
</FocusLock>
There is no legitimate way to do this since iOS kind of wants to only open the keyboard on a user interaction, however you can still achieve this with either using prompt() or using focus() from within a click() event it and will show up.
I am working on Dojo Version 1.8.I have designed one custom widget as below. Its a snippet
<div>
<div>
<input
id ="NZ1",
data-dojo-attch-point = "NZ1"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur : makeAllSmall"
/>
</div>
<div>
<input
id ="NZ2",
data-dojo-attch-point = "NZ2"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur: makeAllSmall"
/>
</div>
</div>
Here is event handler
makeAllSmall : function(evt){
var currVal=evt.target.value;
currVal = currVal.toLowerCase();
/**Some Other business logic on currVal **/
}
This evt is always coming as undefined . I am quite new to Dojo. Am I missing something in HTML side ? I tried to change HTML as below but not luck
<input
id ="NZ2",
data-dojo-attch-point = "NZ2"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur : makeAllSmall"
data-dojo-args="e"
/>
First thing first, is there a typo in the method "onBlurr"? I see there is an extra 'r'. Shouldn't it be "onBlur"?
If you look at the DOJO API documentation for onBlur event, it doesn't pass an event object like what you are expecting
onBlur()
Defined by: dijit/_FocusMixin
Called when the widget stops being "active" because focus moved to something outside of it, or the user clicked somewhere outside of it, or the widget was hidden.
Examples
Example 1
var btn = new Button();
// when /my/topic is published, this button changes its label to
// be the parameter of the topic.
btn.subscribe("/my/topic", function(v){
this.set("label", v);
});
Next, in your event handler, you are trying to change the text to lowerCase and this can be done like
makeAllSmall : function(){
var currVal=this.get("value");
currVal = currVal.toLowerCase();
/**Some Other business logic on currVal **/
}
Another way of doing this without the event handler is to force the ValidationTextBox to convert everything to lowercase using construction parameters like
<input
id ="NZ2",
data-dojo-attach-point = "NZ2"
data-dojo-attach-type = "ecm.widget.ValidationTextBox"
data-dojo-props='lowercase:true'
data-dojo-attach-event = "onBlurr : makeAllSmall"
/>
Note that I have added data-dojo-props='lowercase:true'
Hope this helps.
You should be able to attach a DOM event to your custom widget by:
Using data attribute data-dojo-attach-event in the markup.
And using _AttachMixin passing your callBack function.
Example:
<div id="somenode"><span data-dojo-attach-point="anattachpoint"
data-dojo-attach-event="click: clicked">Click me</span></div>
var MyDijit = declare([ _WidgetBase, _AttachMixin ], {
// .. declaration goes here ..
clicked: function(e) {
// handle event
}
});
// instantiate the dijit instance, which will attach to the 'somenode' div.
var mydijit = new MyDijit({}, dom.byId('somenode'));
mydijit.startup();
I'm needing help with an answer to a previous question
How to limit the number of dropzone.js files uploaded?
where there was a solution to use
Dropzone.options.myAwesomeDropzone = {
accept: function(file, done) {
console.log("uploaded");
done();
},
init: function() {
this.on("addedfile", function() {
if (this.files[1]!=null){
this.removeFile(this.files[0]);
}
});
}
};
But being a js numpty, I don't know where to put this. I assume that my form must have the id myAwesomeDropzone and that the code above needs to be slotted into the dropzone.js document, but where? if you could provide a 'after' and 'before' or replace answer please.
If someone could give me some pointer it'd be great.
My reputation is less than 50 so I couldn't comment on the original thread. If me posting this as a new thread is wrong, please admins don't just chastise me and close it, but move it or do whatever to allow people to provide help accrodingly.
Cheers
Andy
Your html form should be like below. Notice that the
class="dropzone"
and
id="my-dropzone"
The "my-dropzone" ID is important , DropZone takes this as "myDropzone" , ( hyphen removed and camelcased ). So when you refer to this id in DropZone.options , it should be "myDropzone". This is very important.
<div>
<form action="/file-upload" class="dropzone" id="my-dropzone" style="border:2px dotted #337ab7">
<div class="dz-message">
Drag n drop photos here or click to upload.
<br />
<span class="note">(The photos are uploaded to twitter only when the tweet is sent.)</span>
</div>
</form>
</div>
Your should link the css and js file in your html page like so
<script src="./js/dropzone.min.js"></script>
<link href="./css/dropzone.min.css" rel="stylesheet" type="text/css">
On the page load , you should init the dropzone configuration in your JS code for your page as below. I am restricting dropzone to accept only one file and its size should not exceed 5MB.
self.options.maxFilesize = 5; self.options.maxFiles = 1;
Dropzone.autoDiscover = false;
Dropzone.options.myDropzone = {
init: function() {
var self = this;
// config
self.options.addRemoveLinks = true;
self.options.autoProcessQueue = false;
self.options.maxFilesize = 5;
self.options.maxFiles = 1;
self.options.dictFileTooBig =
"Twitter do not allow files greater than 5MB.";
//New file added
self.on("addedfile", function(file) {
console.log('new file added ', file.path);
});
self.on("maxfilesexceeded", function(file) {
alert(
"Only one photo can be attached with the tweet."
);
});
}
};
Now when your page loads , you will see the form & get the drag n drop functionality in your div.
To access the files you can do like below in the javascript on some button click event.
// to get queued files
var myDropzone = Dropzone.forElement("#my-dropzone");
var files = myDropzone.getQueuedFiles();
I work on web accessibility for blind people interacting with a screen reader Jaws and a vocal synthesizer.
I am using x/html with wai-aria and JavaScript to design accessible web pages of a questionnaire user test.
In this kind of application, main difficulty is to face with different behaviors on different browsers and also versions of Jaws screen reader generate different behaviors.
However, problems started after the release of Firefox 4 (and next 4.01).
The same code of a web questionnaire page for blind doesn't work again with new release of Firefox 4.01 browser.
It seems like the same functions of JavaScript is not yet supported.
In fact even if the screen reader is turned off, interaction with “tab” key is blocked. :-(
Before that release 4 of Firefox, interaction was good.
On the contrary on Internet Explorer, interaction with “tab” key it was blocked also on version 8 and 9... and I don’t know why. :-(
Here at end, there is an extract of the code, with a radio button inside a form.
The form is questionnaire for a user test including radio buttons, combo-boxes, multi select checkboxes, test areas and a button for submit.
The behavior of the radio button and other elements in the form should be the following:
The blind uses “tab” key to skip from a the radio button choice to another.
When user reach last choice, if the user have not selected anything, a vocal alert say: 'Please, define your visual disability!'
and the focus go on the first choice of the radio button again.
Otherwise, if the blind have selected one choice, focus go on the next element inside the form.
Each element of the form (for example the radio button), considers two events:
onFocus, when the user focus “goes”
for the first time on the element.
onBlur, when focus changes.
Is there something wrong I am not considering?
AN EXTRACT OF CODE:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="it" lang="it">
<head>
<script type = "text/javascript">
<!-- hide me from older browser>
function removeOldAlert()
{
var oldAlert = document.getElementById("alert");
if (oldAlert)
document.body.removeChild(oldAlert);
}
function addAlert(aMsg)
{
removeOldAlert();
var newAlert = document.createElement("div");
newAlert.setAttribute("role", "alert");
newAlert.setAttribute("aria-live", "rude");
newAlert.setAttribute("id", "alert");
var msg = document.createTextNode(aMsg);
newAlert.appendChild(msg);
document.body.appendChild(newAlert);
}
…
function checkValidity3(aID, num, aMsg)
{
var elem = document.getElementById(aID);
var invalid = true;
for (var loop = 0; loop < window.document.questionario_conoscitivo.tipo_disabilita.length; loop++)
{
if (window.document.questionario_conoscitivo.tipo_disabilita[loop].checked == true)
{
invalid = false;
}
}
if (invalid) {
elem.setAttribute("aria-invalid", "true");
if (num==window.document.questionario_conoscitivo.tipo_disabilita.length-1)
addAlert(aMsg);
} else {
elem.setAttribute("aria-invalid", "false");
removeOldAlert();
}
return invalid;
}
function proseguire(msg1, … msg3, … msg16)
{
if(msg1 == true)
{
…
}
…
else if(msg3 == true)
{
window.document.questionario_conoscitivo.tipo_disabilita[0].focus();
}
…
else if(msg16 == true)
{
…
}
}
function checkRisposta(invalid, … invalid3, … invalid16)
{
result = !(invalid) && … && !(invalid3) && … !(invalid16);
return result;
}
// show me -->
</script>
</head>
<body onload="invalid = true; … invalid3= true; … invalid16= true;">
<form id="questionario_conoscitivo" name="questionario_conoscitivo" action="http://...questionario.php" method="POST" onsubmit="return checkRisposta(invalid,… invalid3, … invalid16);">
…
<div role="dialog" aria-labelledby="messaggio3">
<h2 id="messaggio3"><b>3) Kind of visual disability:</b><br/><br/></h2>
<input type="radio" aria-required="true" id="tipo_disabilita0" name="tipo_disabilita" value="Blind" onFocus="proseguire(invalid, … invalid3, … invalid16);" onblur="invalid3 = checkValidity3('tipo_disabilita0', 0, ‘Please, define your visual disability!');" />
<label for="tipo_disabilita0">Non vedente<br/></label>
<input type="radio" aria-required="true" id="tipo_disabilita1" name="tipo_disabilita" value="Visually Impaired" onblur="invalid3 = checkValidity3('tipo_disabilita1', 1, 'Please, define your visual disability!');" />
<label for="tipo_disabilita1">Ipovedente<br/></label>
<input type="radio" aria-required="true" id="tipo_disabilita2" name="tipo_disabilita" value="None" onblur="invalid3 = checkValidity3('tipo_disabilita2', 2, 'Please, define your visual disability!');" />
<label for="tipo_disabilita2">Nessuna<br/></label>
</div><br/>
…
</form>
</body>
</html>
I can point out one problem, each radio button is labeled with aria-required="true" even though the user need only select one. Use a radio group instead.
I know you asked a different question, but from looking at the code, this was a bigger accessibility issue. Apologies for not answering the question directly, but I hope you get some value from my answer.