Retrieve the "Placeholder" value with Javascript in IE without JQuery - javascript

I have some Javascript code that checks if a browser supports Placeholders and if it doesn't it creates them itself. Now this works on some older browsers but not all, especially IE.
All I need to do it get the "Placeholder" value, at the moment the placeholder in IE9 is "undefined".
Here is my code:
//Test if Placeholders are supported
var test = document.createElement("input");
if ("placeholder" in test) {
var testholder = true;
}
else {
var testholder = false;
}
//Fix unsupported placeholders
function placeHolder(id)
{
var demo = document.getElementById(id);
demo.className = "fix-hint";
demo.value = demo.placeholder;
demo.onfocus = function()
{
if (this.className == "fix-hint")
{
this.value = ""; this.className = "fix-nohint";
}
};
demo.onblur = function()
{
if (this.value === "")
{
this.className = "fix-hint"; this.value = demo.placeholder;
}
};
return false;
}
I am using 0% Jquery, I feel it's too bulky to solve small problems, plus I want to learn pure Javascript. Modernizr is a no too although I may come round to using it at some point.
UPDATE
This is the working code. Tested in IE 8 and 9. (The function call is within an if/else for "placeSupport".)
//Check if placeholders are supported
placeholderSupport = ("placeholder" in document.createElement("input"));
if(!placeholderSupport){
var placeSupport = false;
}else{
var placeSupport = true;}
//Support placeholders in older browsers
function placeHolder (id)
{
var el = document.getElementById(id);
var placeholder = el.getAttribute("placeholder");
el.onfocus = function ()
{
if(this.value == placeholder)
{
this.value = '';
this.className = "fix-nohint";
}
};
el.onblur = function ()
{
if(this.value.length == 0)
{
this.value = placeholder;
this.className = "fix-hint";
}
};
el.onblur();
}

If you're not sure if you're able to use certain functionality/attributes, try caniuse.com - you'll notice that placeholder is not available in IE9.
Try using getAttribute("placeholder")
getAttribute() returns the value of the named attribute on the
specified element. If the named attribute does not exist, the value
returned will either be null or "" (the empty string); see Notes for
details.
EXAMPLE
HTML
<input id="demo" placeholder="Rawr" />
JavaScript
var placeholder = document.getElementById("demo").getAttribute("placeholder");
console.log(placeholder);

Related

Custom vanilla JS for translation does not work on Android Chrome

I've been really struggling to use any (literally any!) client-side (e.g. web browser) translation library. Tested several: jquery-i18next, jquery.i18n, localizejs, translate-js. And guess what - none really worked as expected, not a single one would be just a plug-n-play solution. That's why I decided to write a vanilla Javascript code which would work as a simplest alternative. Here's the code:
let locale;
let dict = {
'en': {...},
'fr': {...}
};
function detectNavigatorLocale() {
const languageString = navigator.language || '';
const language = languageString.split(/[_-]/)[0].toLowerCase();
switch (language) {
case 'en':
return 'en';
case 'de':
return 'de';
default:
return 'en';
}
}
// replacement to $(document).ready() in jQuery
function docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
// helper to get nested value in JSON-like object by dot-path string
function findProp(obj, prop, defval) {
if (typeof defval == 'undefined') defval = null;
prop = prop.split('.');
for (var i = 0; i < prop.length; i++) {
if (typeof obj[prop[i]] == 'undefined')
return defval;
obj = obj[prop[i]];
}
return obj;
}
let switchers = document.querySelectorAll('[data-locale]');
for (let i = 0; i < switchers.length; i++) {
switchers[i].onclick = function () {
let newLocale = switchers[i].getAttribute('data-locale');
locale = newLocale;
translate();
};
}
function translate(newLocale) {
let els = document.querySelectorAll('[data-i18n]');
for (let i = 0; i < els.length; i++) {
let path = els[i].getAttribute('data-i18n');
let translatation = findProp(dict[locale], path, 'undefined');
els[i].innerHTML = translatation;
}
// trigger repainting
window.dispatchEvent(new Event('resize'));
};
docReady(function () {
locale = detectNavigatorLocale();
translate();
});
And to make it work, the only thing to do in HTML is to add attributes to the elements which require translation as <p data-i18n="some.path.in.dictionary">fallback text</p>. To change the language I used <li data-locale="en">EN</li> and similar.
But here's the tricky part: why Desktop browser shows expected results, but several tested mobile browsers refuse to a) emit event on the locale switcher element and b) in some (Brave, Dolphin) even navbar in collapsed state does not unfold. I expect that latter is related to the JS handling in general in the selected browser, but why in Chrome for example the same code does not work?
First of all I replaced the bad practice of setting onclick with the following:
function switchLocale(loc) {
locale = loc;
translate();
}
let switchers = document.querySelectorAll('[data-locale]');
switchers.forEach(
function(switcher) {
switcher.addEventListener("click", function() {
// alert(switcher.id);
switchLocale(switcher.getAttribute('data-locale'));
})
}
)
and tested that it works fine. But the actual problem was that z-index was too low and the image below was overlayered above mobile nav. :)

How to set multiple properties in Javascript

I want to disable an element and also set its placeholder in Javascript.
I'm able to do this with the below code (I'm referring to the writecontent element).
function toggleType() {
var type = document.querySelector('select[name="type"]').value;
if(type == 'Review') {
aboutreview.style.visibility = ('visible');
document.querySelector('.writecontent').disabled = true;
document.querySelector('.writecontent').placeholder = "Not available in Review";
} else if (type == 'Discussion' || '') {
aboutreview.style.visibility = ('hidden');
document.querySelector('.writecontent').disabled = false;
Instead of calling the element twice, how would I set the disabled and placeholder at the same time when calling the element the first time?
May be by storing the element reference in a variable.
const writeElem = document.querySelector('.writecontent');
if (writeElem) {
writeElem.disabled = true;
writeElem.placeholder = "Not available in Review";
}

Re-writing simple jQuery into pure JavaScript

I'm building a JavaScript plugin which will bolt onto other websites.
The whole thing is written with pure JS but there's one bit I haven't been able to get away from jQuery with:
var key = "some_key";
var selector = "#my_input, input[name=my_input], .someInputs";
jQuery(document).on('change', selector, function() {
doSomething(key, this.value);
});
The reason I want to avoid jQuery is that I expect this JS to be included in a wide range of sites, many of which won't have jQuery. Some will have other frameworks already installed such as Mootools, some will have old versions of jQuery where .on() isn't supported, etc.
That, and I am ideally trying to keep it very lightweight, so adding in jQuery just for this tiny task seems excessive.
Here’s some futuristic JavaScript that does exactly the same thing:
var key = "some_key";
var selector = "#my_input, input[name=my_input], .someInputs";
document.addEventListener('change', function (e) {
if (e.target.matches(selector)) {
doSomething(key, e.target.value);
}
});
However, several browsers only support it with a prefix, so it’ll be closer to this:
var matches = (function () {
var names = ['matches', 'matchesSelector', 'mozMatchesSelector', 'webkitMatchesSelector', 'msMatchesSelector'];
for (var i = 0; i < names.length; i++) {
var name = names[i];
if (name in HTMLElement.prototype) {
return HTMLElement.prototype[name];
}
}
return null;
})();
var key = "some_key";
var selector = "#my_input, input[name=my_input], .someInputs";
document.addEventListener('change', function (e) {
if (matches.call(e.target, selector)) {
doSomething(key, e.target.value);
}
});
Assuming the selector isn’t dynamic and you need delegation, you can still do the verbose, manual check:
var key = "some_key";
document.addEventListener('change', function (e) {
var target = e.target;
if (target.id === 'my_input' ||
target.nodeName === 'INPUT' && target.name === 'my_input' ||
(' ' + target.className + ' ').indexOf(' someInputs ') !== -1) {
doSomething(key, target.value);
}
}, false);
As #T.J. Crowder points out, although this works for input elements, you’ll need to check an element’s parents in many cases. Here’s some even more futuristic JavaScript to accomplish the task:
function* ascend(element) {
do {
yield element;
} while ((element = element.parentNode));
}
var key = "some_key";
var selector = "#my_input, input[name=my_input], .someInputs";
document.addEventListener('change', function (e) {
var match = Array.from(ascend(e.target)).find(x => x.matches(selector));
if (match) {
doSomething(key, match.value);
}
});
If you smashed Firefox Nightly and Chrome together, this would work in that browser. We don’t have that, but feel free to shim Array.prototype.find!

Too much recursion

can anyone tell me where the loop comes from?
JS:
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
}
else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
}
if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = getwords(zahlm1++);
}
else {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = "";
}
document.getElementById('makroclick').innerHTML = data_split[zahl];
document.getElementById('makroclick').onclick = getwords(zahl++);
document.getElementById('makroclickp1').innerHTML = data_split[zahlp1];
document.getElementById('makroclickp1').onclick = getwords(zahlp1++);
if (typeof(data_split[zahlp1]) == "undefined") {
document.getElementById('makroclickp1').innerHTML = "";
document.getElementById('makroclickp1').onclick = "";
}
document.getElementById('makroclickp2').innerHTML = data_split[zahlp2];
document.getElementById('makroclickp2').onclick = getwords(zahlp2++);
if (typeof(data_split[zahlp2]) == "undefined") {
document.getElementById('makroclickp2').innerHTML = "";
document.getElementById('makroclickp2').onclick = "";
}
HTML:
<div id="makroclickm2" onclick="" class="makroclick"></div>
<div id="makroclickm1" onclick="" class="makroclick"></div>
<div id="makroclick" onclick="getwords(0);" class="makroclick_center"></div>
<div id="makroclickp1" onclick="getwords(1);" class="makroclick"></div>
<div id="makroclickp2" onclick="getwords(2);" class="makroclick"></div>
(Not complete Code)
The function is called once onload.
Thx in advance!
In the lines like this:
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
You're assigning the onclick handler to the result of getwords(zahlm2++), not to that function itself.
If, as I suspect, the code above actually is the getwords function, that means it's calling itself (recursively).
Instead, write:
document.getElementById('makroclickm2').onclick = function() {
getwords(zahlm2++);
}
This doesn't answer the question (or even try to). However, it works to address the over-abundance of repeated code.
// instead of repeating the document.getElementById
// many times over...
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
// get the element once
var elm = document.getElementById('makroclickm2')
// and use it many times over
elm.innerHTML = ""
elm.onclick = null // do not use strings here
This will make the code much easier to follow (please use appropriate variable names).
Also, do not use strings with the onclick attribute. Use functions instead.
Happy coding.
You also might consider using event registration rather than direct assignment. That way you don't have to worry about accidentally overwriting anything later down the road. #Alnitak's solution would look more like this:
var myEl = document.getElementById('makroclickm2');
var myFunc = function() {
getwords(zahlm2++);
}
if (myEl.addEventListener) myEl.addEventListener("click", myFunc, false);
else if (myEl.attachEvent) myEl.attachEvent("onclick", myFunc);
else myEl.onclick = myFunc;
Obviously that's pretty verbose, but it would be easy to write a quick helper function takes myEl and myFunc as inputs and handles everything for you.
You can read more about event registration at http://www.quirksmode.org/js/events_advanced.html
This part might give you a ton of problems:
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = getwords(zahlm2++);
}
else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = "";
}
if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = getwords(zahlm1++);
}
else {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = "";
}
Try using else if instead of another block of if statements. Also, I'd use function(){} instead of "" (and getwords(), as that evaluates the function and doesn't set it to be run when the even is called):
if (zahl > 1) {
document.getElementById('makroclickm2').innerHTML = data_split[zahlm2];
document.getElementById('makroclickm2').onclick = function(){getwords(zahlm2++)};
} else if (zahl > 0) {
document.getElementById('makroclickm1').innerHTML = "";
document.getElementById('makroclickm1').onclick = null;
document.getElementById('makroclickm1').innerHTML = data_split[zahlm1];
document.getElementById('makroclickm1').onclick = function(){getwords(zahlm1++)};
} else {
document.getElementById('makroclickm2').innerHTML = "";
document.getElementById('makroclickm2').onclick = null;
}

Jquery Evolution from simple plain javascript

i have been using jquery for a while now but only thing i know about jquery is probably a dozen of functions that get my job done. but i want to understand how jquery evolved from simpl plain javascript i.e how
$("#xyz").val();
is converted to
document.getElementById('xyz').value;
i have searched for my answer on the web but most of the writers are happy to show how you can hook on to different DOM elements with jquery, selector details etc. but nothing can be found about how actually the transition was made. can anyone refer me to some tutorial where i can get my required material?
thanks
jQuery is not a compiler. jQuery does not get compiled into javascript.
.val is a method of an object. The jQuery object.
Specifically it is
function (value) {
if (!arguments.length) {
var elem = this[0];
if (elem) {
if (jQuery.nodeName(elem, "option")) {
// attributes.value is undefined in Blackberry 4.7 but
// uses .value. See #6932
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
// We need to handle select boxes special
if (jQuery.nodeName(elem, "select")) {
var index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type === "select-one";
// Nothing was selected
if (index < 0) {
return null;
}
// Loop through all the selected options
for (var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++) {
var option = options[i];
// Don't return options that are disabled or in a disabled optgroup
if (option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName(option.parentNode, "optgroup"))) {
// Get the specific value for the option
value = jQuery(option).val();
// We don't need an array for one selects
if (one) {
return value;
}
// Multi-Selects return an array
values.push(value);
}
}
return values;
}
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
if (rradiocheck.test(elem.type) && !jQuery.support.checkOn) {
return elem.getAttribute("value") === null ? "on" : elem.value;
}
// Everything else, we just grab the value
return (elem.value || "").replace(rreturn, "");
}
return undefined;
}
var isFunction = jQuery.isFunction(value);
return this.each(function (i) {
var self = jQuery(this),
val = value;
if (this.nodeType !== 1) {
return;
}
if (isFunction) {
val = value.call(this, i, self.val());
}
// Treat null/undefined as ""; convert numbers to string
if (val == null) {
val = "";
} else if (typeof val === "number") {
val += "";
} else if (jQuery.isArray(val)) {
val = jQuery.map(val, function (value) {
return value == null ? "" : value + "";
});
}
if (jQuery.isArray(val) && rradiocheck.test(this.type)) {
this.checked = jQuery.inArray(self.val(), val) >= 0;
} else if (jQuery.nodeName(this, "select")) {
var values = jQuery.makeArray(val);
jQuery("option", this).each(function () {
this.selected = jQuery.inArray(jQuery(this).val(), values) >= 0;
});
if (!values.length) {
this.selectedIndex = -1;
}
} else {
this.value = val;
}
});
}
If we break the above wall down we can get
function (value) {
if (arguments.length === 0) {
return (this[0].value || "")
}
this.value = val;
return this;
}
Of course jQuery has a lot more code to deal with various edge cases and special things.
In essence jQuery takes a selector. finds the elements. Stores them internally then returns you an object.
This object has all kinds of methods that allow you to mutate the underlying dom objects stored internally. .val is one of them.
There are plenty of articles on how jQuery works (there are screencasts too).
jQuery, as you've noticed, is basically a bunch of methods operating on an array of elements. It is also intended to normalize browser differences under the hood.
Take the basic usage $("#xyz").val();
I can even tell you what jQuery is doing behind the scenes, but I don't think you really want to know. :)
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},
// ...
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// ...
},
// ...
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
So basically $(selector) means newjQuery.fn.init(selector), it's just a shortcut for easier typing (and also to prevent the "bug" where fogetting new binds this to the global object, instead of the current instance).
Also, the so-called plug-ins added as jQuery.fn.ext are mapped to jQuery.fn.init.prototype as you can see in the last line, it's another shortcut. So when you call $(selector) everything that is added to jQuery.fn will also be on jQuery.fn.init.prototype and so the new instance will have those methods as $(selector).ext(...).
// as you use it today
jQuery.fn.plugin = function ( ... ) { ... }
$(selector).plugin( ... )
// as it would be without shortcuts
jQuery.fn.init.prototype.plugin = function ( ... ) { ... }
(new jQuery.fn.init(selector)).plugin( ... )

Categories

Resources