I have the following: FIDDLE
The placeholder works fine and dandy until you type something, ctrl + A, and delete. If you do that, the placeholder disappears and never shows up again.
What's wrong? How can I have a placeholder for a contenteditable div?
HTML:
<div class="test" placeholder="Type something..." contenteditable="true"></div>
CSS:
.test {
width: 500px;
height: 70px;
background: #f5f5f5;
border: 1px solid #ddd;
padding: 5px;
}
.test[placeholder]:empty:before {
content: attr(placeholder);
color: #555;
}
Thanks.
While searching for the same problem I worked out a simple mixed css-JavaScript solution I'd like to share:
CSS:
[placeholder]:empty::before {
content: attr(placeholder);
color: #555;
}
[placeholder]:empty:focus::before {
content: "";
}
JavaScript:
jQuery(function($){
$("[contenteditable]").focusout(function(){
var element = $(this);
if (!element.text().trim().length) {
element.empty();
}
});
});
Updated fiddle
from Placeholder in contenteditable - focus event issue
[contenteditable=true]:empty:not(:focus):before{
content:attr(data-ph);
color:grey;
font-style:italic;
}
I got this solution from: https://codepen.io/flesler/pen/AEIFc
Basically put this css code:
[contenteditable=true]:empty:before{
content: attr(placeholder);
pointer-events: none;
display: block; /* For Firefox */
}
And have the placeholder attribute in your contenteditable div.
I've created a live demo: "Placeholder for content-editable divs", by HTML & CSS.
Also, Codepen: https://codepen.io/fritx/pen/NZpbqW
Ref: https://github.com/fritx/vue-at/issues/39#issuecomment-504412421
.editor {
border: solid 1px gray;
width: 300px;
height: 100px;
padding: 6px;
overflow: scroll;
}
[contenteditable][placeholder]:empty:before {
content: attr(placeholder);
position: absolute;
color: gray;
background-color: transparent;
}
<textarea class="editor"
placeholder="Textarea placeholder..."
></textarea>
<br/>
<br/>
<div class="editor"
contenteditable
placeholder="Div placeholder..."
oninput="if(this.innerHTML.trim()==='<br>')this.innerHTML=''"
></div>
I see what you mean. In your fiddle I typed in a few characters and deleted it using 'ctrl-a' and 'delete', and the placeholder reappeared.
However, it seems as if when you hit 'enter' within the contenteditabele div it creates a child div containing the line break <div><br></div> creating an issue with the :empty pseudo-class which only targets elements with no child elements.**
Check it out in chrome developer tools or whatever you use.
From developer.mozilla.org
The :empty pseudo-class represents any element that has no children at all. Only element nodes and text (including whitespace) are considered. Comments or processing instructions do not affect whether an element is considered empty or not.
Ctrl-a will delete the text, but leaves the child div. Might be able to fix this by adding some javascript.
some fixes:
1) $element.text().trim().length - it solved problems with <div><br/></div> and
2) data-placeholder attr instead of placeholder - it is true way
3) common selector $("[contenteditable]") - it is true way
4) display: inline-block; - fix for Chrome and Firefox
JavaScript:
jQuery(function($){
$("[contenteditable]").blur(function(){
var $element = $(this);
if ($element.html().length && !$element.text().trim().length) {
$element.empty();
}
});
});
HTML:
<div data-placeholder="Type something..." contenteditable="true"></div>
CSS:
[contenteditable]:empty:before {
content: attr(data-placeholder);
color: grey;
display: inline-block;
}
It feels like I am repeating myself, but why not to check contenteditable element mutations? Trying to bind everything to event that are changing content are pain in the butt. What if You need to add button (For example paste), or change content dynamically (javascript). My approach would be using MutationObservers. Demo fiddle
HTML:
<div class="test" id="test" placeholder="Type something..." contenteditable="true"></div>
CSS:
.test {
width: 500px;
height: 70px;
background: #f5f5f5;
border: 1px solid #ddd;
padding: 5px;
}
.test[placeholder]:empty:before {
content: attr(placeholder);
color: #555;
}
JavaScript:
var target = document.querySelector('#test');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (target.textContent == '') {
target.innerHTML = '';
}
});
});
var config = { attributes: true, childList: true, characterData: true };
observer.observe(target, config);
Updating Christian Brink's answer, you could/should check for more events. You can do so by simply doing:
// More descriptive name
var $input = $(".placeholder");
function clearPlaceHolder() {
if ($input.text().length == 0) {
$input.empty();
}
}
// On each click
$input.keyup(clearPlaceHolder);
// Probably not needed, but just in case
$input.click(clearPlaceHolder);
// Copy/paste/cut events http://stackoverflow.com/q/17796731
$input.bind('input', (clearPlaceHolder));
// Other strange events (javascript modification of value?)
$input.change(clearPlaceHolder);
Finally, the updated JSFiddle
As swifft said, you can fix this with some super simple JS. Using jQuery:
var $input = $(".test");
$input.keyup(function () {
if ($input.text().length == 0) {
$input.empty();
}
});
On each keystroke it checks whether there's any input text present. If not, it whacks any child elements that may have been left behind by user interaction with the element -- e.g. the <div> swifft describes.
This solution worked for me. I'd converted this solution from angular to pure javaScript
In .html
<div placeholder="Write your message.." id="MyConteditableElement" onclick="clickedOnInput = true;" contenteditable class="form-control edit-box"></div>
In .css
.holder:before {
content: attr(placeholder);
color: lightgray;
display: block;
position:absolute;
font-family: "Campton", sans-serif;
}
in js.
clickedOnInput:boolean = false;
charactorCount:number = 0;
let charCount = document.getElementsByClassName('edit-box')[0];
if(charCount){
this.charactorCount = charCount.innerText.length;
}
if(charactorCount > 0 && clickedOnInput){
document.getElementById("MyConteditableElement").classList.add('holder');
}
if(charactorCount == 0 && !clickedOnInput){
document.getElementById("MyConteditableElement").classList.remove('holder');
}
getContent(innerText){
this.clickedOnInput = false;
}
I have this function, and I always use to prevent this kind of things.
I use my function in this way:
var notEmpty = {}
notEmpty.selector = ".no-empty-plz"
notEmpty.event = "focusout"
notEmpty.nonEmpty = "---"
neverEmpty(notEmpty)
And I just add the no-empty-plz to the Elements I that don't want to be empty.
/**
* Used to prevent a element have a empty content, made to be used
when we want to edit the content directly with the contenteditable=true
because when a element is completely empty, it disappears U_U
*
* #param selector
* #param event
* #param nonEmpty:
* String to be put instead empty
*/
function neverEmpty(params) {
var element = $(params.selector)
$(document).on(params.event, params.selector, function() {
var text = $(this).html()
text = hardTrim(text)
if ($.trim(text) == "") {
$(this).html(params.nonEmpty)
}
});
}
params is actually a json, so selector = params.selector as you can see
And hardTrim is also another fucntion I created is like a trim but includs   and <br/>, etc
function hardTrim(text) {
if (!exists(text)) {
return ""
}
text = text.replace(/^\ \;|<br?\>*/gi, "").replace(/\ \;|<br?\>$/gi, "").trim();
return text
}
This works for me and it's trim the long placeholder if the input is too small
[contenteditable="true"][placeholder]:empty:before {
content: attr(placeholder);
position: absolute;
left: 5px;
font-size: 13px;
color: #aaa;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 100%;
direction: ltr;
}
This happens because when you ctrl+A then delete, there is a <br> remaining in the innerHTML of the textarea. A simple jQuery/javascript solution can do the trick to empty out the textarea:
$(document).on('input','.test',function(){
if(this.innerHTML == '<br>'){
$(this).html('');
}
});
let contenteditableDiv = document.getElementById('contenteditableDiv');
contenteditableDiv.addEventListener('focus', function() {
let phs = this.querySelector('.placeholder-span');
if (phs != null) {
if (!this.hasOwnProperty('placeholderSpan')) {
this.placeholderSpan = phs;
}
phs.remove();
document.getSelection().setPosition(this, 0);
}
});
contenteditableDiv.addEventListener('focusout', function() {
if (this.textContent.trim().length == 0 && this.hasOwnProperty('placeholderSpan')) {
this.replaceChildren(this.placeholderSpan);
}
});
.placeholder-span {
opacity: 0.5;
}
<div id="contenteditableDiv" contenteditable="true"><span class="placeholder-span">Type something...</span></div>
And if You want to avoid contenteditable HTML formatting problems (leading/trailing spaces) and write it like a normal person:
<div id="contenteditableDiv" contenteditable="true">
<span class="placeholder-span">Type something...</span>
</div>
Then add:
window.addEventListener('load', function() {
let contenteditableDiv = document.getElementById('contenteditableDiv');
contenteditableDiv.innerHtml = contenteditableDiv.innerHtml.trim();
});
And if You want the placeholder to stay unitll there's input You need to put proper logic into mousedown, beforeinput and input event listeners.
Related
Here's the parent div:
<div
id="comment"
placeholder="Your comment"
class="form-control ellipsesDropdown"
contenteditable="true"
#input="CommentChanged($event)"
> <!-- comments are divided into spans and divs with spans containg normal text and divs containing tags -->
<span></span>
</div>
Now when a user clicks a Tag, I create the Tag as follows:
const newTag = document.createElement('div');
newTag.setAttribute("tabindex", "-1");
newTag.style.cssText = "background-color: rgba(29,155,209,0.1); color: #1264a3; display: inline-block; font-weight: bold;";
const tagContent = document.createTextNode(`#${p}`); // imagine p is an input argument
newTag.append(tagContent);
// attach on key down event listener
newTag.onkeydown = function(event) {
console.log(event)
};
// add tag to the comment div
document.getElementById("comment")!.appendChild(newTag);
However, I get nothing when I press keys in the tag div, click events do work though. I took a look at How can I use a 'keydown' event listener on a div? and have added the tabindex attribute.
I've also tried attaching the event listener as:
newTag.addEventListener('keydown', function(event) {
console.log(event);
});
But this still doesn't work.
Any idea about what's going on?
EDIT: As requested, here's a codesandbox link: https://codesandbox.io/s/blue-bird-tdidr
EDIT 2: I've added more code from my project that basically implements to a certain extent what I'm trying to accomplish. Think about Twitter/Instagram/Slack, when you #someone as you're typing the post then perhaps some options appear for who to # and when you click someone then that "tag" is added to your post. In the example, go ahead and write something, and include #, you'll see a list of options open, click either bread or toast and see it become a tag. What I'm trying to do it add the on keydown EventListener on the Tag so go ahead and see that it doesn't work!
I see you want to create a comment function i guess? But the way you do its not the Vue.js way. Here is a simple comment box example:
let el = new Vue({
el: "#app",
template: "",
data(){
return {
comment: "",
comments: []
}
},
methods: {
addComment(){
let txt = this.convertTags(this.comment);
console.log(txt);
var d = new Date();
var n = d.toLocaleTimeString();
this.comments.push({
commentText: txt,
time: n
});
this.comment = "";
},
clickedTag(tag){
console.log(tag);
},
convertTags(str){
let strArr = str.split(" ");
let mappedArr = strArr.map(el => {
if(el.includes("#")){
el = `<span onclick='el.clickedTag("${el.replace("#", "")}")' class='tag'>${el}</span>`;
}
return " " +el;
});
this.template = mappedArr.join("")
return this.template;
}
}
});
#app {
width: 80%;
margin: 0 auto;
}
.comment {
background: #6c5ce7;
width: 100%;
margin: 5px 0;
color: white;
padding: 8px 5px;
}
input {
margin: 0 auto;
width: 100%;
display: block;
padding: 5px;
}
.tag {
color: black;
background: white;
padding: 2px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="comment in comments" class="comments">
<div class="comment">
<p v-html="comment.commentText"></p>
<small>{{ comment.time }}</small>
</div>
</div>
<input type="text" v-model="comment" #keyup.enter="addComment">
</div>
Apparently I don't need to add an event listener to the divs I'm adding. I can just set their contenteditable attribute to false as user SleepWalker menstions in his answer here: How to delete an HTML element inside a div with attribute contentEditable?
So my answer would then become:
...
newTag.setAttribute("contenteditable", "false")
document.getElementById("comment")!.appendChild(newTag);
This allows me to delete the tag in one go!
This is my html code for displaying a editable textbox and is used as a "memo" element inside a webpage (inside a div tag).
contenteditable="true" name="choice1" class="textfield" max="872">Enter your Memo Here!
CSS:
.textfield {
max-width: 800px;
width: 800px;
border: 1px solid black;
padding: 8px;
margin: 20px;
float:right;
position: relative;
}
Javascript:
var textfields = document.getElementsByClassName("textfield");
for(i=0; i<textfields.length; i++){
textfields[i].addEventListener("keypress", function(e) {
if(this.innerHTML.length >= this.getAttribute("max")){
e.preventDefault();
return false;
}
}, false);
}
However when I fill the editable div area with alot of spaces (" "), it takes less than the declared 872 characters to reach the maximum limit. Does anyone know why and have a solution? Thanks.
Use textContent instead of innerHTML.
The textContent property sets or returns the textual content of the specified node, and all its descendants.
The innerHTML property sets or returns the HTML content (inner HTML) of an element.Which will include tags
In the below example I have set the max as 20
var textfields = document.getElementsByClassName("textfield");
for (i = 0; i < textfields.length; i++) {
textfields[i].addEventListener("keypress", function(e) {
if (this.textContent.length >= this.getAttribute("max")) {
e.preventDefault();
console.log('max reached') ;
return false;
}
}, false);
}
<div contenteditable="true" name="choice1" class="textfield" max="20">Enter your Memo Here!</div>
I'm attempting to create one function that will change the class of one of three elements when the mouse goes over that particular element (and only that element).
However whenever I mouse over any element, the class changes for all three. Why? Here's what I did:
<-- The HTML -->
<p class="font1" id="change4_1" onmouseover="Q4()"> Menu1</p>
<p class="font1" id="change4_2" onmouseover="Q4()"> Menu2</p>
<p class="font1" id="change4_3" onmouseover="Q4()"> Menu3</p>
/* The CSS*/
p.font1 {
color:blue;
white-space:nowrap;
display: inline-block;
}
p.font2 {
color:#2E2E2E;
white-space:nowrap;
display: inline-block;
}
// The Javascript //
function Q4() {
var NAME1 = document.getElementById("change4_1");
if (NAME1.mouseover = true) {
NAME1.className = "font2";
}
var NAME2 = document.getElementById("change4_2");
if (NAME2.mouseover = true) {
NAME2.className = "font2";
}
var NAME3 = document.getElementById("change4_3");
if (NAME3.mouseover = true) {
NAME3.className = "font2";
}
}
I'm certain the JavaScript is the issue but I included everything anyway.
To compare use ==(Equality Operator) or ===(Strict Equality Operator).
You're not comparing the value in the if statement. You're assigning the value true to the variable. To compare the value in the if statement, use == or === operator.
if (NAME1.mouseover=true)
Should be
if (NAME1.mouseover == true)
Or
if (NAME1.mouseover === true)
You don't need Javascript to change styles on mouseover, you can take advantage of CSS :hover class.
p.font1 {
color: blue;
white-space: nowrap;
display: inline-block;
}
p.font1:hover {
color: #2E2E2E;
}
<p class="font1" id="change4_1">Menu1</p>
<p class="font1" id="change4_2">Menu2</p>
<p class="font1" id="change4_3">Menu3</p>
Update
As your JS code is invalid, NAME1.mouseover = true, you can use following code, if you want to use JS to change some properties of HTML element on mouseover.(I'll still recommend to use CSS approach)
function Q4(el) {
el.classList.add('font2');
}
p.font1 {
color: blue;
white-space: nowrap;
display: inline-block;
}
p.font2 {
color: #2E2E2E;
white-space: nowrap;
display: inline-block;
}
<p class="font1" id="change4_1" onmouseover="Q4(this)">Menu1</p>
<p class="font1" id="change4_2" onmouseover="Q4(this)">Menu2</p>
<p class="font1" id="change4_3" onmouseover="Q4(this)">Menu3</p>
You're assigning the element's mouseover property to true in each if statement. This is successful and equates to being true so each if statement is being run. You can't test the element's mouseover property because that's not part of the DOM for elements.
The easiest way to accomplish what you want is to change your CSS's p.font2 to p.font1:hover
However, if you're trying to learn about triggering JavaScript functions with mouseover try passing the argument this to the onmouseover function, IE Q4(this). The function can then refer to the element that was moused over more directly.
<html><head>
<style>
p.font1 {
color: blue;
white-space: nowrap;
display: inline-block;
}
p.font2 {
color: #2E2E2E;
white-space: nowrap;
display: inline-block;
}
</style>
<script>
function Q4(element)
{
element.className='font2';
}
</script>
</head>
<body>
<p class="font1" id="change4_1" onmouseover="Q4(this)"> Menu1</p>
<p class="font1" id="change4_2" onmouseover="Q4(this)"> Menu2</p>
<p class="font1" id="change4_3" onmouseover="Q4(this)"> Menu3</p>
</body>
</html>
This won't change the style back on mouse out though. You could easily write that attribute too.
Since that boils down to one line of code, you could just change it to onmouseover="this.className='font2';"
Most people adding JavaScript event handlers wind up using something like jQuery to help them keeping the script separate from the markup (the CSS only :hover selector does that too). I've demonstrated that here and below:
<html><head>
<style>
p.font1 {
color: blue;
white-space: nowrap;
display: inline-block;
}
p.font2 {
color:#2E2E2E;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js">
</script>
<script>
$( document ).ready(function() {
$( "p.font1" ).on({
"mouseover": function() {
console.log( "hovered!" );
var elem = $( this );
elem.addClass( "font2" );
},
"mouseout": function() {
console.log( "unhovered!" );
var elem = $( this );
elem.removeClass( "font2" );
}
});
});
</script>
</head>
<body>
<p class="font1" id="change4_1"> Menu1</p>
<p class="font1" id="change4_2"> Menu2</p>
<p class="font1" id="change4_3"> Menu3</p>
</body>
</html>
What this does, apart from loading the jQuery library and binding it to $, is, when the document is loaded and ready, it selects all the elements that are of type p with the class font1 and adds event handler functions to them for the mouseover event and mouseout event. These functions in turn log to the JavaScript console when triggered (useful when you're debugging some of your work), get the referring element on which the event was triggered, and then either add or remove a class name to the elements class attribute. So you would see the p tag's class change from "font1" to "font1 font2" and back. That's why the font2 css is changed to only override the specifically changed color.
I hope this better explains what was going on in your example, and what to do about it.
I have a page with two areas. There are boxes in each area. If the user clicks on a box in the top area, it gets moved to the bottom and vice versa. This works fine for the first movement. Theoretically, I should be able to move them back and forth between sections as I please.
Box HTML:
<div id="top-area">
<div class="top-box" id="blue-box"></div>
<div class="top-box" id="yellow-box"></div>
<div class="top-box" id="green-box"></div>
</div>
<hr/>
<div id="bottom-area">
<div class="bottom-box" id="red-box"></div>
<div class="bottom-box" id="gray-box"></div>
</div>
I use jQuery.remove() to take it out of the top section and jQuery.append() to add it to the other. However, when I try to move a box back to its original position, the event that I have created to move them doesn't even fire.
jQuery/JavaScript:
$(".top-box").on('click', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
});
$(".bottom-box").on('click', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
});
I have verified that the classes I am using as jQuery selectors are getting added/removed properly. I am even using $(document).on() to handle my event. How come my boxes are not triggering the jQuery events after they are moved once?
Please see the Fiddle: http://jsfiddle.net/r6tw9sgL/
Your code attaches the events on the page load to the elements that match the selector right then.
If you attach the listener to #top-area and #bottom-area and then use delegated events to restrict the click events to the boxes, it should work like you expect. See .on: Direct and Delegated Events for more information.
Use the below JavaScript:
$("#top-area").on('click', '.top-box', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
});
$("#bottom-area").on('click', '.bottom-box', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
});
Alternatively:
You could also change .on() to .live(), which works for "all elements which match the current selector, now and in the future." (JSFiddle)
JSFiddle
Here's another way you could work it:
function toBottom ()
{
var item = $(this);
item.remove();
item.off('click', toBottom);
item.on('click', toTop);
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
}
function toTop ()
{
var item = $(this);
item.remove();
item.off('click', toTop);
item.on('click', toBottom);
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
}
$(".top-box").on('click', toBottom);
$(".bottom-box").on('click', toTop);
#top-area, #bottom-area {
height: 100px;
border: 1px solid black;
padding: 10px;
}
.top-box::before {
content: "Top";
}
.bottom-box::before {
content: "Bottom";
}
#blue-box, #red-box, #yellow-box, #green-box, #gray-box {
width: 100px;
cursor: pointer;
float: left;
margin: 0 5px;
text-align: center;
padding: 35px 0;
}
#blue-box {
background-color: blue;
}
#red-box {
background-color: red;
}
#yellow-box {
background-color: yellow;
}
#green-box {
background-color: green;
}
#gray-box {
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-area">
<div class="top-box" id="blue-box"></div>
<div class="top-box" id="yellow-box"></div>
<div class="top-box" id="green-box"></div>
</div>
<hr/>
<div id="bottom-area">
<div class="bottom-box" id="red-box"></div>
<div class="bottom-box" id="gray-box"></div>
</div>
This basically removes the listener that switched the object to bottom to a listener that switches the object to the top and viceversa.
I have a one field form (text input and submit button). Here is the form code:
<form id="new_skill" class="new_skill" method="post" action="/skills" >
<li>
<input id="resume-field" class="field field288" type="text"
value="Type a speciality you want to add to your profile"
title="Type a speciality you want to add to your profile"
name="skill[label]"></input>
</li>
<li class="td80">
<input class="button button-add button-add-disabled"
type="submit" value="ADD +" name="commit"></input>
</li>
</form>
Using javascript, if text is entered in the text field, the submit button should be unclickable. If there is no text in the field, it should be clickable. I am doing that by using javascript to remove and/or put back the button-add-disabled class. Here is the javascript:
(function($){
$(document).on('focusin', '#resume-field', function() {
$(this).parents().find('.button-add-disabled').removeClass('button-add-disabled');
}).on('focusout', '#resume-field', function(){
if(this.value==' '||this.title==this.value) {
$(this).parents().find('.button-add').addClass('button-add-disabled');
} else {
$(this).parents().find('.button-add').removeClass('button-add-disabled');
}
});
$('.button-add-disabled').click(function(){
return false;
});
}(jQuery));
And here is the css:
.button-add { width: 49px; height: 28px; border: solid 1px #8c8c8c; display: block;
font-size: 11px; line-height: 28px ; color: #fff; text-align: center;
font-family: 'Ubuntu', sans-serif; transition: none; margin: 0 0 0 auto;
border-radius: 3px; }
.button-add:hover { text-decoration: none;
-webkit-transition:none;
-moz-transition:none;
-ms-transition:none;
-o-transition:none;
transition:none;
}
.td80 .button-add { margin-left:35px !important; }
.button-add-disabled { background: url(/assets/add-specialities-disabled.png)
repeat-x 0 0; box-shadow: 0 0 0 0; margin-left:35px; }
.button-add-disabled:hover { background: url(/assets/add-specialities-disabled.png)
repeat-x 0 0; box-shadow: 0 0 0 0; }
The classes are changing as expected and the javascript is working. For some reason though, even if .button-add-disabled is not applied to the form element, the form element is still returning false and therefore won't submit. When "button-add-disabled" is removed by the javascript, the form should submit. I can see the server logs. If I remove the line from the javascript "return: false", the form works, So i know the form itself works. I'm pretty sure something is wrong with the javascript. Any ideas?
That's not how that works. Events are bound to elements, which are reached via selectors; they are not bound to selectors.
When you bind the event directly to the element, the event is now bound to that element until you explicitly unbind it. The original selector is no longer relevant.
You need to do this, or something like it:
$('.button-add-disabled').click(function(){
return !$(this).hasClass('button-add-disabled');
});
That is, test whether the button is currently disabled by your class at the point the event is raised.
As an aside, this...
if(this.value==' '||this.title==this.value) {
$(this).parents().find('.button-add').addClass('button-add-disabled');
} else {
$(this).parents().find('.button-add').removeClass('button-add-disabled');
}
should be this:
var disabled = this.value == ' ' || this.title == this.value;
$(this).parents().find('.button-add').toggleClass('button-add-disabled', disabled);
You want to set/remove the disabled attribute of the input element, not set a CSS style which is for display purposes only
$('#resume-field').on('change', function() {
if ($(this).val().length == 0) {
$(this.form).find('input[type=submit]').attr('disabled', false).removeClass('button-add-disabled');
} else {
$(this.form).find('input[type=submit]').attr('disabled', true).addClass('button-add-disabled');
}
})
jsFiddle Demo
Also be sure that you handle the submission of the form when the user presses enter in the input field, you can do that using the jQuery .submit event handler and preventing the default behaviour. It is also essential you handle this server side.
EDIT: I just noticed what the CSS was doing, updated answer.