3
\$\begingroup\$

Here is a link to my problem

$('#name').focus(function() {
    if ($(this).val() == 'Full Name*')
        $(this).val('');
        }).blur(function() {
    if($(this).val() == '')
        $(this).val('Full Name*');
});
    $('#email').focus(function() {
    if ($(this).val() == 'Email Address*')
        $(this).val('');
        }).blur(function() {
    if($(this).val() == '')
        $(this).val('Email Address*');
});
    $('#subject').focus(function() {
    if ($(this).val() == 'Subject*')
        $(this).val('');
        }).blur(function() {
    if($(this).val() == '')
        $(this).val('Subject*');
});
    $('#msg').focus(function() {
    if ($(this).val() == 'Your Message*')
        $(this).val('');
        }).blur(function() {
    if($(this).val() == '')
        $(this).val('Your Message*');
});

I've been trying to simplify this code, but because of my limited javascript knowledge I haven't been able to achieve this. I'm almost 100% sure that this could be written in much simpler - DRY form.

\$\endgroup\$

migrated from stackoverflow.com Oct 23 '14 at 21:15

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ I'm looking at the higher-level problem here and I'm wondering if placeholder is an acceptable solution, unless you have a need to support older browsers. \$\endgroup\$ – rink.attendant.6 Oct 23 '14 at 18:10
3
\$\begingroup\$

Use a custom date attribue, lets say placeholder on your inputs, and then give them a common class as well:

<input type="text" id="email" data-placeholder="Email Address" class="required" />
<input type="text" id="name" data-placeholder="Full Name" class="required" />
<input type="text" id="subject" data-placeholder="Subject" class="required" />
<input type="text" id="msg" data-placeholder="Your Message" class="required" />

And then use 1 event for all!

$(".required").focus(function() {
    var placeholder = $(this).data("placeholder");
    if (this.value == placeholder) this.value = "";
}).blur(function() {
    if (this.value == "") this.value = $(this).data("placeholder");
}).blur(); //trigger on load

A fiddle: http://jsfiddle.net/odpu5gbn/

\$\endgroup\$
  • 1
    \$\begingroup\$ What about to remove the whole code and use placeholder instead? \$\endgroup\$ – Regent Oct 23 '14 at 18:11
  • 1
    \$\begingroup\$ @Regent -- Always an option - unless old browser support is an issue. \$\endgroup\$ – tymeJV Oct 23 '14 at 18:11
  • \$\begingroup\$ Believe it or not, there are a significant number of people who are still using a browser that doesn't support it, primarily older businesses where it is (or is perceived as) too expensive to be worth upgrading. \$\endgroup\$ – Kevin B Oct 23 '14 at 18:13
  • 1
    \$\begingroup\$ Suggestion: remove required class, and select the elements by $('[data-placeholder]'). \$\endgroup\$ – Elias Soares Oct 23 '14 at 18:14
  • 1
    \$\begingroup\$ Well, data-placeholder should have the same behavior in entire page, so, i don't see any problems. A way to speed up, is use $('input').on('focus', '[data-placeholder]', handler). \$\endgroup\$ – Elias Soares Oct 23 '14 at 18:25
2
\$\begingroup\$

This is not the answer for your problem, BUT:

If you are trying to put a placeholder to your input elements, why don't you just use HTML5 placeholder attribute?

W3schools Attribute Placeholder

<input type="text" id="email" placeholder="Email Address" />
  • This is not supported in Internet Explorer 9 and earlier versions.
\$\endgroup\$
  • 1
    \$\begingroup\$ Why down-vote? It is a solution for the problem. Most simple than this? \$\endgroup\$ – Elias Soares Oct 23 '14 at 18:15
  • \$\begingroup\$ Downvotes are not mine, but note MDN says (emphasis mine): Do not use the placeholder attribute instead of a <label> element. Their purposes are different: the <label> attribute [sic] describes the role of the form element; that is, it indicates what kind of information is expected, the placeholder attribute is a hint about the format the content should take. There are cases in which the placeholder attribute is never displayed to the user, so the form must be understandable without it. \$\endgroup\$ – Frédéric Hamidi Oct 23 '14 at 18:17
  • \$\begingroup\$ Sure Frédéric. In some small forms like login forms or newsletter form, or like this answer box in Stackoverflow, the placeholder works! BTW, the question author question is about a placeholder. \$\endgroup\$ – Elias Soares Oct 23 '14 at 18:22
  • 1
    \$\begingroup\$ Indeed, I was just pointing out that implementing the placeholder through scripting would not be subject to the limitations mentioned on MDN, in addition to supporting more browsers. In practice, all the HTML5-compliant browsers I've used so far have indeed always displayed the placeholder, but you never know. Maybe the downvoters went through that train of thought. \$\endgroup\$ – Frédéric Hamidi Oct 23 '14 at 18:27
  • 2
    \$\begingroup\$ @EliasSoares total score of -1 is not good, that's for sure, but at least there is +6 reputation. I still think that placeholder is not a bad idea (especially due to reducing code to zero). But these damned old browsers make life complicated even in SO... \$\endgroup\$ – Regent Oct 23 '14 at 18:28
1
\$\begingroup\$

You are right to question something repetitive like that.

Here's a direct replacement for your idea.

function setValue(selector, text) {
    $(selector).focus(function() {
        if ($(this).val() == text)
            $(this).val('');
    }).blur(function() {
        if($(this).val() == '')
            $(this).val(text);
    });
}

setValue('#name', 'Full Name*');
setValue('#email', 'Email Address*');
setValue('#subject', 'Subject*');
setValue('#msg', 'Your Message*');
\$\endgroup\$
  • 2
    \$\begingroup\$ Use this.value instead of $(this).val() \$\endgroup\$ – tymeJV Oct 23 '14 at 19:22
  • \$\begingroup\$ The repeated use of $(this) is also unnecessary. It's better to assign it to a variable once and reuse it: var $this = $(this);. The OP's code suffers from this as well. @tymeJV: +1 for suggesting the use of native browser properties for something so trivial. Don't be afraid to get your hands dirty with the DOM. \$\endgroup\$ – Greg Burghardt Oct 24 '14 at 14:05
0
\$\begingroup\$

Basically all your code revolves around 2 types of operation:

  • check if the current value equals another value
  • set a new value

Refactor that common logic into 2 separate functions:

function testIf(value) {
    return $(this).val() == value;
}
function setValue(value) {
    $(this).val(value);
}

You need to pass this as a context, which will allow you to keep your code inside the function as is:

testIf.call(this, 'Full Name*');
setValue.call(this, '');

Of course this approach focuses on your JavaScript code only. It all depends how much you want to impact your existing code.

\$\endgroup\$
0
\$\begingroup\$

To throw my hat in the ring, this creates a basic patch for the placeholder attribute in non compatible browsers:

JsFiddle: http://jsfiddle.net/d9qwxtmu/

$(document.documentElement).on("blur", function(event) {
    var target = event.target,
        placeholder = target.getAttribute("placeholder");

    if (/^\s*$/.test(placeholder) || "placeholder" in target) {
        // Either the placeholder doesn't exist or the browser already supports the
        // "placeholder" attribute, so bail out. Addmittedly, this is a weak test
        // for browser support, but should suffice as long as you don't explicitly
        // set the "placeholder" property on a text box.
        return;
    }

    if ("value" in target) {
        target.value = target.value === placeholder ? "" : target.value;
    }
});

This works with the following HTML:

<input type="text" placeholder="First name">
<input type="text">

If browsers natively support the placeholder attribute, we just bail out of this blur event handler. If the placeholder is an empty value, we also bail out. Only if the browser does not have a placeholder property on the event target and the placeholder value is not empty do we check the value of the INPUT tag.

Furthermore, since it uses jQuery's on method, event delegation is utilized so that only one snippet of JavaScript is needed for the whole page. The mere addition of <input type="text" placeholder="foo"> will trigger this polyfill, even if the text box is created and appended at runtime.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy