Adding/removing elements with javascript

Discussion in 'JavaScript' started by duveit, Nov 9, 2008.

  1. #1
    I have a couple of objects which I use to make and remove elements, that is working just fine. But I can't get it to work with existing elements in the DOm tree.

    I think there is some error with how the event listeners are set up, but I can't spot it.., when I use the buttons I create with js, they remove the elements added dynamically instead of the elements itselfs.

    Basically I'm adding a event to body onLoad which is calling a method "initBody" to iterate through every child of a wrapping element, and adds a span element and event to each which belongs to a certain classname.

    Any clue on what I'm doing wrong here would be of great help as I'm rather new with javascript.

    I cant link to this yet, but there is an example at http://gjenklang.no/js/

    Code is as following
    
    /*
     * Copying and moving elements
     * syntax: Move.element('e', target', 'move/copy');
     */
    var Move = {
        // todo: fix elementname recursivly
        fixName: function(node, number){
            var amt = node.childNodes.length - 1;
            for (var i = 0; amt >= i; i++) {
                if (node.childNodes[i].name) {
                    node.childNodes[i].name = node.childNodes[i].name + number;
                }
                if (node.childNodes[i].childNodes.length > 0) {
                    Move.fixName(node.childNodes[i], number);
                }
            }
        }, //copying elements
        copy: function(e, target, name){
            var eId = document.getElementById(e);
            var copyE = eId.cloneNode(true);
            var cLength = copyE.childNodes.length - 1;
            copyE.id = name;
            if (copyE.childNodes.length > 0) {
                Move.fixName(copyE, name);
            }
            document.getElementById(target).appendChild(copyE);
            return copyE;
        },
        element: function(e, target, type, name){
            var eId = document.getElementById(e);
            if (type == 'move') {
                document.getElementById(target).appendChild(eId);
            }
            
            else 
                if (type == 'copy') {
                    this.copy(e, target, name);
                }
        }
    };
    
    
    /*
     * ******** DOM, get/add/remove ***
     */
    var Dom = {
        get: function(el){
            if (typeof el === 'string') {
                return document.getElementById(el);
            }
            else {
                return el;
            }
        },
        add: function(el, dest){
            var el2 = this.get(el);
            var dest2 = this.get(dest);
            dest2.appendChild(el2);
        },
        remove: function(el){
            var el2 = this.get(el);
            el2.parentNode.removeChild(el2);
        }
    };
    
    var Event = {
        add: function(){
            if (window.addEventListener) {
                return function(el, type, fn){
                    Dom.get(el).addEventListener(type, fn, false);
                };
            }
            else 
                if (window.attachEvent) {
                    return function(el, type, fn){
                        var f = function(){
                            fn.call(Dom.get(el), window.event);
                        };
                        Dom.get(el).attachEvent('on' + type, f);
                    };
                }
        }()
    };
    
    function initBody(){
        var td = Dom.get("verv-wrap");    
        var num = 0;
        for (var i = 0; td.childNodes.length > i; i++) {
            if (td.childNodes[i].className == "dotted") {
                var txt = document.createElement("span");
                txt.innerHTML = "remove " + num;
                txt.className = "pointer";
                Dom.add(txt,td.childNodes[i]);
                
                Event.add(txt, 'click', function(ex){
                    Dom.remove(td.childNodes[i]);
                });
    			num++;
            }
        }
    }
    
    /*
     *** Run at start
     */
    Event.add(window, 'load', function(){
    
    	initBody();
    	    
        var inc = 0;
        
        Event.add('add', 'click', function(){
            inc++;
            var copy = Move.copy('verv-template', 'verv-wrap', 'verv-div-'+inc);
            var txt = document.createElement("span");
            txt.innerHTML = "remove " + inc;
            txt.className = "pointer";
            Dom.add(txt, copy);
            
            Event.add(txt, 'click', function(ex){
                Dom.remove(copy);
            });
        });
    });
    
    
    Code (markup):

     
    duveit, Nov 9, 2008 IP
  2. wayfarer07

    wayfarer07 Peon

    Messages:
    34
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    0
    #2
    It seems to be working ok at the example you gave, did you get it fixed, or am I missing something?
     
    wayfarer07, Nov 9, 2008 IP
  3. duveit

    duveit Peon

    Messages:
    3
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #3
    What is not working, is the buttons to remove the elements allready there, called "posted elements".
    I'm trying to get those to behave similar as to the ones you create by the "add element" button.
     
    duveit, Nov 9, 2008 IP
  4. LogicFlux

    LogicFlux Peon

    Messages:
    2,925
    Likes Received:
    102
    Best Answers:
    0
    Trophy Points:
    0
    #4
    
        for (var i = 0; td.childNodes.length > i; i++) {
    
            if (td.childNodes[i].className == "dotted") {
                var txt = document.createElement("span");
                txt.innerHTML = "remove " + num;
                txt.className = "pointer";
                Dom.add(txt,td.childNodes[i]);
    
                Event.add(txt, 'click', function(e) {
                  
                      if (e.target) var targ = e.target;
                      else if (e.srcElement) var targ = e.srcElement;
    
                      if (targ.nodeType == 3) // defeat Safari bug
                        targ = targ.parentNode;
    
                      Dom.remove(targ.parentNode);
                });
    
    			      num++;
            }
        }
    
    
    Code (markup):

    You were using

    Dom.remove(td.childNodes);

    Which didn't work because when the function was invoked it took the value of i, which was whatever i was in that scope, which was whatever it was in the last iteration. You could have solved that by using a closure, but you still had the problem that if you remove items that come before the last item, then the indexes get screwed up. So it's best just to pass the parent of the event target.
     
    LogicFlux, Nov 9, 2008 IP
    duveit likes this.
  5. duveit

    duveit Peon

    Messages:
    3
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #5
    Thanks a lot LogicFlux , you made my day :)

    Rather new to javascript, but interface scripting seems to become a unavoidable "evil", mostly doing php.

    Now, this solution by loading the buttons with the onload event for the body might be a ugly way of doing it, incase the user's browser doesnt support js, I suppose. But it's meant for a limited userbase.

    I was about to give up this as a whole and rather add checkboxes to which to remove, but this way is so much more elegant I'd say.
     
    duveit, Nov 10, 2008 IP