Jquery improvement of this script - Adding and removing items from list I've been getting help with this script seen below. It allows one input box to be used to put values into a text area and also display a list of the items. The items can be deleted once inserted:

http://jsfiddle.net/ZTuDJ/50/

// If JS enabled, disable main input
$("#responsibilities").prop('disabled', true);
// $("#responsibilities").addClass("hidden");

// If JS enabled then add fields
$("#resp").append('&lt;input placeholder="Add responsibility" id="resp_input" &gt;&lt;/input&gt;&lt;input type="button" value="Add" id="add"&gt; ');

// Add items to input field
var eachline='';
$("#add").click(function(){
    var lines = $('#resp_input').val().split('\n');
    var lines2 = $('#responsibilities').val().split('\n');
    if(lines2.length&gt;10)return false;
    for(var i = 0;i &lt; lines.length;i++){
        if(lines[i]!='' &amp;&amp; i+lines2.length&lt;11){
        eachline += lines[i] + '\n';
        }    
    }

    $('#responsibilities').text($("&lt;div&gt;" + eachline + "&lt;/div&gt;").text()).before("&lt;li&gt;"+$("&lt;p&gt;"+lines+"&lt;/p&gt;").text()+"&lt;span class='right'&gt;&lt;a href='#'&gt;Remove&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;");

    $('#resp_input').val('');
});    

$(document).on('click', '.right a', function(){
    var el = $(this).closest('li')
    var index = $('li').index(el);
    var text = eachline.split('\n');
    text.splice(index, 1);
    eachline = text.join('\n')
    $('#responsibilities').text(eachline)
    el.remove()
})


I was wondering if it would be possible to tag links in the list with the following information:

&lt;span refid="1"&gt;Remove&lt;/span&gt;


By tagging the links in this way I was thinking I could easily point to them with jquery if I wanted to delete it or later edit it.

Is there room to simplify this script in this way?
What's good here:


It's fairly simple
Using prop over attr


What I did not like


Using HTML strings in code makes code very hard to modify later on. It's hard to debug and might cause potential issues (like making XSS easy for example).
No separation of concerns. You're treating your HTML like your source of knowledge instead of backing up your data with a model in the background. This is very harmful and I personally consider it a big design flaw. Your business logic (in this case the list items) and your presentational layer (the DOM nodes) is the same here. Every time you want to operate on the list you have to query the DOM. This is not only slow, but it becomes very nasty very fast as your code logic begins to expand.


There are frameworks like KnockoutJS that do data binding making this trivial to accomplish in just a few lines of code. However since you wanted a solution that has no 'magic' (Which I totally appreciate by the way) let's see what would be a simple JavaScript solution would look like.

Short note, I'm doing JavaScript with function constructors here since a lot of people find it easier, personally I'd use object initializers.

Here is a working fiddle

First, we'll have a data model for a responsibility.

//This is our element in the view model.
function Responsibility(text){
    this.text=text;
}


Next, we'll need to store all our responsibilities. We'll use an array:

// a list of our responsibilities, an actual view model to back our data
var responsibilities = []; 


Now, we'll want a render function, that'll take our elements, and turn them into actual DOM objects. We'll spit it into two. First, we'll render the list item:

function renderResponsibility(rep,deleteClick){
    var el = document.createElement("li");
    var rem = document.createElement("a");
    rem.textContent = " Remove";
    rem.onclick = deleteClick;
    var cont = document.createElement("span");
    cont.textContent = rep.text;
    el.appendChild(cont);
    el.appendChild(rem);
    return el;
}


On renderResponsibility another alternative would be to use a templating engine, but you said no extra libraries so I'm keeping my word :)

Now, our general render:

//render our actual elements
function render(){
    respList.innerHTML = "";
    // note, foreach needs a modern browser but can easily be shimmed
    responsibilities.forEach(function(responsibility,i){
        var el = renderResponsibility(responsibility,function(){
            responsibilities.splice(i,1);//remove the element
            render();//re-render
        });
        respList.appendChild(el);
    });
    //update the text area;
    respTextArea.textContent = responsibilities.map(function(elem){
       return elem.text;//get the text. 
    }).join("\n");
}


Finally, let's add the functionality to the Add button:

//events 
addButton.onclick = function(e){
    var text = newResp.value;
    var resp = new Responsibility(text);
    responsibilities.push(resp);
    render();
    newResp.value = "";
}


And we're done :)

Just to tease:


Here is a solution in KnockoutJS
Here is a shorter solution in KnockoutJS without using an object for responsibility
Here is a solution in AngularJS


Also here is a more 'jQuery' version of the vanilla solution. As you can see a DOM manipulation library isn't very useful when building an application.