I'm using select2 and fetching available options from the server with this query function
var recipientsTimeout;
this.loadRecipients = function (query) {
clearTimeout(recipientsTimeout);
recipientsTimeout = setTimeout(function(){
data.transmitRequest('lookupcontacts', { search: query.term }, function(resp){
query.callback({ results: resp.items });
});
}, 500);
};
It uses our own ajax layer, and delays searching until the user stops typing, and it works fine. The only small issue is that if the user types some text, then immediately backspaces over it, my last timeout will still fire, and an ajax request will be fired, and ignored. This doesn't cause any problems, but it's less than optimal.
Is there any (preferably non-brittle) way to fetch whatever the current text is? It seems as though the query object sent in has an element property, which is a jQuery wrapper of the original hidden input I set select2 up with, but there's no direct way I can see to get the actual textbox that the user is typing in. Obviously I could inspect it and easily figure out the dom pattern and build up a selector from the hidden element back to what the user is typing in, but I really hate doing that, since the specific layout could easily change in a future version.
So what is the best way to get the currently entered text, so I could do a quick check on it when the setTimeout expires, and I'm about to run my ajax request.
I'm using 4.0.3 and the way I did it is this:
$("#mySelect2").data("select2").dropdown.$search.val()
The hidden input element (where you initialize select2 on) gets a data property select2, which contains references to all elements, that are used by select2. So you could do something like this:
var hiddenInputSelector = '#e1',
select2 = $(hiddenInputSelector).data('select2'),
searchInput = select2.search;
if($(searchInput).val() === '')
clearTimeout(recipientsTimeout);
This is not in the docs though, so it might change in the future.
In select2 version 4.0.3 this works for me, whereas the others did not:
$('.select2-search__field')[0].value;
I do something like this to get the current search term:
list.data("select2").search[0].value;
Related
I have a little problem setting up a virtualPageView which should override the URL which is sent to google when no result is present.
Heres what I have as JavaScript code:
function returnNoSearchResultsGoogleTagManagerCode($searchterm){
if ($searchterm == "") return "";
$requestUri = $_SERVER['REQUEST_URI'] . "&no_result=".$searchterm;
$js = "<script>
$(document).ready(function(){
dataLayer.push({
'event':'empty_result',
'virtualPageURL':'".$requestUri."'
});
});
</script>";
return $js;
}
As you can see, I want to use an event trigger (empty_result).
In google, I use a Trigger to determine if the Page is a no result Page. First i created a custom Variable with custom JS
function(){
if (document.getElementsByClassName('ga-no-result').length > 0){
return true;
}else{
return false
}
}
The class is set, if the SearchEngine can't find a result. So far so good.
I also created a dataLayer variable to hold the virtualPageURL
Now I need an event which is triggered if the variable is true.
Finally I created a Tag with type PageView which is fired when the event occurs:
Until now it seems okay, the Tag is properly configured (i guess) but if I do a search which has no result, the Page URL is not overridden
The Tag is properly fired and the variables are filled. The overview of the dataLayer shows a correct dataLayer event.
But the PageURL is not overridden... Even if I wait a whole day, the category isn't sent to google.
What am I doing wrong?
I would be very thankful if someone would have an idea or even a solution :)
Thanks in advance
exa.byte
UPDATE:
Hey, I forgot to mention, that I want to use the new page variable as the string which google should use to determine the searchterm and the searchcategory
In Google Analytics I configuered the search as the "q" parameter and the "no_result" as the category.
Is it even possible to change the string which google will parse in the end?
To send a virtual pageview to Google Analytics, the field you need to change is page not {{Page Url}} , also the title field is often used.
That's really the only two things you need to do to send a simple virtual pageview.
Extra: I always start my pagepath with /virtual/ to be able to recognize which ones are virtual pageviews easily in GA
For virtual page view you have to change Field "page" - in your GTM-OnSearchEmptyResult you are changing "{{Page URL}}" - I don't think that's correct way to send virutal pageview. Also if you need to change hostname use Fieldname "hostname".
In preview mode you will not see Page URL changed in Variables Tab, you have to go to the actual GA tag that is fired and check it's values. You can either do this in GTM's preview tool or you can use standard developer tools - Network Tab and see what values are being sent to GA:
You can see "dl" parameter is the current page, if you set up virtual page you should also see parameter called "dp" this is going to be the new value of page in your GA.
If you want to setup virtual pageview you have to use page instead of {{Page URL}} in your fieldname and for Document title use title in you fieldname.
for more field reference of google analytics follow below link
https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#hitType.
If you don't want to mess around with custom Tag Manager events it's still possible to use the good old ga method, even if you don't include the Analytics code on the page. You just need to fetch the right tracker dynamically, as explained by Simo Ahava in this thread.
if (typeof ga === "function") {
ga.getAll().forEach((tracker) => {
tracker.set('page', '/my/path'); // <- change here
tracker.send('pageview');
});
}
I also put it in a gist here.
thanks for your help. I think I got rid of the Problem and have solved it now. I will describe my solution below:
The solution is quite simple.
I had an error/ spelling error # google backend. I set the search_category parameter to "no_results", but used "no_result" for implementation...
Pretty dumb, but sometimes you just won't see the wood for the trees...
I created a new Trigger as helper "HelperDomReady" to trigger the only if DOM is ready and the variable "isEmptySearch" equals "(bool)true"
Now I can see the searchterms which have no result in google backend in the "sitesearch categories" summary. Since I won't set the parameter at all, if the search had at least one hit, the site-search category shows "not-set" for successful results. Therfore the category-section will only show searches without a hit. Problem solved :)
Disadvantage: The searchterm is also listed in the normal list. But I think this is negligible
What I'm trying to do:
Collect all the class and id names in an Ace Editor html script.
Right now my plan is to detect user changes (.on('change'...)) and get the current token using the cursor position. If the token is a not 'unquoted' 'attribute-value' type, I want to iterate back through previous tokens in order to find the 'attribute-name' type token to which that 'attribute-value' belongs and identify whether it is a class or id (I can't just detect the creation of an 'attribute-name' token because the user can go back and change the attribute-values later without changing the name, and I need to detect those changes).
I can do everything except for get previous tokens. I looked up some documentation and the TokenIterator is supposed to be able to do that, but when I try to do something like var iter = new TokeIterator(), my console says that TokenIterator is undefined. I've searched google over and over, but found no results. If the truth is out there I'm obviously not using the right words to find it, but they're the only words I've got.
Is some way built into Ace to iterate through tokens? I know I'm not seeing all the properties and methods on the editor instance object when I console log it, because I can use methods in my script that I can't see in that log. Is there one there that does what I want?
If not, how do I load the TokenIterator? I think something similar went on when I tried to use SnippetManager a while back and it turned out I actually had to do this to make it work:
var tillPageLoaded = setInterval(function() { // Makes sure page doesn't load forever on startup
if( document.readyState === 'complete') {
clearInterval(tillPageLoaded);
ace.config.loadModule('ace/ext/language_tools', function () {
editor.insertSnippet( myString );
});
}
}, 5);
Is this the same kind of situation? If so, what needs to be in .loadModules(...)? Do I need to reference a script somewhere? Does it need to be loaded some other way?
Is there built in functionality for Ace that would already do everything I want?
Other than that, if anyone has any better ideas of how to go about this with Ace, those would be very welcome.
you can get TokenIterator by using
var TokenIterator = ace.require("ace/token_iterator").TokenIterator
see https://github.com/ajaxorg/ace/blob/master/lib/ace/mode/folding/xml.js#L38 for an example of its usage.
My html page with SELECT and OPTIONS values sets one of the options as a default.
Were the user to choose a different option, which then takes him to a new page, I’d like to preserve that value so the next time home page is generated the value the user selected should remain on display, rather than the original default value, when the window reloads.
How do I do this in javascript?
I had tried to save values via a DOM capture of the selected value, but I don’t seem to be able to change that original default value.
E.g.,, one line of code reads:
window.location.reload();
yet were I to use “hold values” to capture the user’s selected option that differs from the default option, like so:
var holdPick = document.getElementById(“uPick”).value;
window.location.reload();
document.getElementById(“uPick”).value = holdPick;
that won’t do the trick, and I know not why.
When you reload a page, all the JavaScript is reloaded too. So, that's why the JavaScript snippet you posted doesn't seem to be working... The line after window.location.reload(); isn't even run at all. If you want to have a value that persists between page loads, you'll need to set and retrieve a cookie. Check out the JavaScript document.cookie API at MDN. That should tell you what you need to know about storing and retrieving your value in a cookie.
Why: every time var holdPick is executed it will create variable from scratch.
Second line tells the browser to reload page, so the third line never gets the chance to be executed.
I'd recommend usage of HTML5 Web Storage
if (sessionStorage.uPick) { //check if variable has been set already
document.getElementById(“uPick”).value = sessionStorage.uPick;
} else {
sessionStorage.clickcount = document.getElementById(“uPick”).value;
}
you can use cookies also, but I don't think it is as straight forward.
Evening! I'm trying to log in into a website with zombie.js, but I don't seem to be able to make it work.
Oh and the website is in Finnish, but it's not very hard to understand, two text fields and a button. First is for username, second for password and the button is the log in button.
At the moment my log in code is as follows:
var Browser = require("zombie");
browser = new Browser();
browser.visit("https://www.nordnet.fi/mux/login/startFI.html?cmpi=start-loggain",
function () {
// Here I check the title of the page I'm on.
console.log(browser.text("title"));
// Here I fill the needed information.
browser.document.getElementById("input1").value ="MYUSERNAME";
browser.document.getElementById("pContent").value ="MYPASSWORD";
// And here it fails. I try to submit the form in question.
browser.document.getElementById("loginForm").submit();
setTimeout(function () {
// This is here to check that we've submitted the info and have been
// redirected to a new website.
console.log(browser.text("title"));
}, 2000);
});
Now I know that I maybe should have used zombie's own "fill" method, but I tried that with no luck so I tried something new.
All I get from this is an error:
Y:\IMC\Development\Web\node_modules\zombie\lib\zombie\forms.js:72
return history._submit(_this.getAttribute("action"), _this.getAttribute(
^
TypeError: Cannot call method '_submit' of undefined
Now if I log that browser.document.getElementById("loginForm") it clearly does find the form, but alas, it doesn't like it for some reason.
I also tried the "conventional" method with zombie, which is using that log in button on the web page and pressing it. The problem is that it's not actually a button, just an image which has a link attached to it, and it's all inside <span>. And I have no idea how I can "click" that button.
It has no ID on it, so I can't use that, then I tried to use the text on it, but because it has umlauts on it I can't get it to work. Escaping the ä with /344 only gave an error:
throw new Error("No BUTTON '" + selector + "'");
^
Error: No BUTTON 'Kirjaudu sisään'
So yeah, that didn't work, though I have no idea why it doesn't recognize the escaped umlaut correctly.
This is my first question, the second one is a minor one, but I though why not ask it here too now that I've written this text.
If I get all this to work, can I somehow copy the cookie that this log in gives me, and use that in my YQL for screen scraping? Basically I'm trying to scrape stock market values, but without the log in the values are 15min deferred, which isn't too bad, but I'd like it to be live anyhow.
After couple of tests using zombie I came to the conclusion that it's still to early to use it for serious testing. Nevertheless, I came up with working example of form submit (using regular .submit() method).
var Browser = require("zombie");
var assert = require("assert");
browser = new Browser()
browser.visit("http://duckduckgo.com/", function () {
// fill search query field with value "zombie"
browser.fill('input[name=q]', 'mouse');
// **how** you find a form element is irrelevant - you can use id, selector, anything you want
// in this case it was easiest to just use built in forms collection - fire submit on element found
browser.document.forms[0].submit();
// wait for new page to be loaded then fire callback function
browser.wait().then(function() {
// just dump some debug data to see if we're on the right page
console.log(browser.dump());
})
});
As you can see, the clue is to use construct browser.wait().then(...) after submitting the form, otherwise browser object will still refer to the initial page (the one passed as an argument to visit method). Note: history object will contain address of page you submitted your form to even if you don't wait for the page to load - it confused me for a bit, as I was sure that I should already see the new page.
Edit:
For your site, the zombie seems to be working ok (I could submit the form and get "wrong login or password" alert). There are some JS errors but zombie isn't concerned with them (you should debug those however to see if the script are working ok for regular users). Anyhow, here's the script I used:
var Browser = require("zombie");
var assert = require("assert");
browser = new Browser()
browser.visit("https://www.nordnet.fi/mux/login/startFI.html?cmpi=start-loggain", function () {
// fill in login field
browser.fill('#input1', 'zombie');
// fill in password field
browser.fill('#pContent', 'commingyourway');
// submit the form
browser.document.forms[0].submit();
// wait for new page to be loaded then fire callback function
browser.wait().then(function() {
console.log('Form submitted ok!');
// the resulting page will be displayed in your default browser
browser.viewInBrowser();
})
});
As side note: while I was trying to come up with working example I've tried to user following pages (all have failed for different reasons):
google.com - even though I filled query box with a string and submitted the form I didn't get search results . Reason? Probably google took some measures to prevent automatic tools (such as zombie) to browse through search results.
bing.com - same as google - after submitting the form I didn't get search results. Reason? Probably same as for google.
paulirish.com - After filling in the search query box and submitting the form zombie encountered script errors that prevent it from completing the page (something about missing ActiveX from charts script).
perfectionkills.com - Surprisingly here I've encountered the same problems as with Paul Irish site - page with search results couldn't be loaded due to javascript errors.
Conclusion: It's not so easy to force zombie into doing your work after all... :)
Yesterday I posted this question which is answered but it lead to another problem.
I have the following code using jquery validation plugin:
//array of success messages and randomly select one
var messages = ["Good!", "Great!", "Awesome!", "Super!", "Nice!","Yay!", "Success!", "Ok!", "Perfect!","Sweet!" ];
function successMessage(label) {
return messages[Math.floor(Math.random() * messages.length)];
}
Then my validation code success
...success: function(label) {
if(!$(label).hasClass("valid")){
label.addClass("valid").text(successMessage());
}
}...
What is happening is that each time the form is being valid (on keyup or foucus) it regenerates a success message. I figured since i was adding the class "valid" a logical step would be to check if the label has the "valid" class and is so don't add a message because it already has one. This however isn't working. Any other ideas would be great.
Edit: So after further research and thinking. I'm pretty sure the problem is that the class of "valid" is being removed and added each time time form is validated (on keyup, submit, etc) I think the easiest thing to do may be to select the value of the label and look to see if the result matches the array, if so then don't do anything else add a success message. I could be wrong. I also don't think I articulated the question the best the first time. It just looks silly to have the validation message change while the user is typing.
EDIT 2 After the many suggestions for clarification and example code I am posting this link http://jsfiddle.net/Ye3Ls/20/ if you type into a field until you get a success message then keep typing you'll see what the problem is. I'm using the validation plugin found here Thanks for all your patients as I sort though how to get this to work. I think i may need to use something like in_array or has_value()
Don't need label as a parameter for successMessage.
function successMessage() {
return messages[Math.floor(Math.random() * messages.length)];
}
I believe that if label is already a jQuery object doing this: $(label) will create a new label jQuery object attached to jQuery. Try this:
if(!label.hasClass("valid")){
label.addClass("valid").text(successMessage());
}
Or
if(label.not(".valid")){
label.addClass("valid").text(successMessage());
}
Or even better:
label.not(".valid").addClass("valid").text(successMessage());
[EDIT] after question asked in comment
if(label.text() === ''){
label.not(".valid").addClass("valid").text(successMessage());
}
else {
label.addClass("valid");
}
I'm assuming that you need to add the valid class to label. If you don't then remove the else statement.
I'm also assuming that the only way for text to be in label is through successMessage. Therefore, you will not need to add any text to label. It will stay the same.
On a side note, if the plug-in is changing the classes of your HTML elements then that is a serious side-effect of the code and I personally wouldn't put up with that.
Now the more logical thing that is probably happening is that you are reloading your content after doing your submission. If that is true then all the jQuery manipulations to the DOM you did before submission will be lost, because of new content be reloaded.
It would be really important in the future to add a link to the actual plug-in and more complete code to work with. #Nick Craver uses jsfiddle.net and I use jsbin.com to post sample code. This can be a more collaborative effort on all our parts to be able to reproduce and solve the problem.
[EDIT 1A]
Here it is
The problem is that the label is being created more than once. This plug-in in my opinion is not so easy to work with.
I had to change the error placement and success logic.
errorPlacement: function(label, element) {
// position error label after generated textarea
var name = element.attr('name');
if ($('#' + name + '_label').length === 0) {
label.attr('id', name + '_label');
label.insertAfter(element);
if (element.is("textarea")) {
label.css({'padding-left': '105px'})
}
}
},
success: function(label) {
var name = label.attr('for');
$('#' + name + '_label').not('.valid').removeClass('error').addClass('valid').text(successMessage());
}
It looks like you mean to say:
$(label).addClass("valid").text(successMessage());
rather than:
label.addClass("valid").text(successMessage());
If label is a variable, and label.addClass("valid") works fine, why don't you verify using:
if(!((label).hasClass("valid"))){
instead of
if(!$(label).hasClass("valid")){