skip to Main Content

I got dynamic add/remove on my web page and when I click ‘+’ adding new box and it contains label and on labels there is ‘-‘, means remove so if I try remove last box and add new box there is no problem with queue. But If I tried to remove at the middle of the box and add new box its get last box number. For example I got ‘1,2,3,4’ and delete ‘4’ and click add new box new list like ‘1,2,3,4’ but when I remove ‘2’ and again add new box ‘1,3,4,4’ and I can’t fix this can’t figure at the algorithm and code and here is my code. Thanks for helping me !

<script>
        let counter = 1 + @counterf;
        let textBox = "";
        let hob = document.getElementById("hob")
        function addBox()
        {
            if (counter<10)
            {
                
                let div = document.createElement("div");
                div.setAttribute("class","form-group");
                div.setAttribute("id","box_"+counter);
                
                let textBox = "<input class='mybox' type='button' value='-' onclick='removeBox(this)'><label> İçerik</label><input type='text' name='ProductFeature.Feature"+counter+"' class='myinput form-control myinput' id='ProductFeature.Feature"+counter+"'>";
                
                div.innerHTML = textBox;
                
                hob.appendChild(div);
                
                counter++;
            }
        }
        
        function removeBox(ele)
        {
            counter=counter-1;
            ele.parentNode.remove();
            
        }
    </script>

and here is my image from website(I can’t upload directly image here cuz I am new, I am sorry for that.

Idea: Maybe I can do a loop by id of form, div or something and if element of something is empty and make counter that number but I can’t do that.

4

Answers


  1. Because you don’t give to function a dynamic place to add. In your code, you are giving ID according to counter. if we say the counter is 4 after you remove an element it becomes 3 but it doesn’t look at the div was on the which index. While you removing you should get which element has been removed and you should make the counter according to its id. After you do that if you remove your 2. div you will get id like box_2. Then you can splice it and get the 2 and make your next counter 2.

    But better way is creating an random id for each element. And if you remove that you can get its id with same way and make it counter. If you don’t remove just make another random counter.

    Login or Signup to reply.
  2. Think about how the counter variable changes when you add/remove a box and what value it contains after adding N boxes.

    If you add 4 boxes (without removing any), counter will be 5. After that, if you remove any box, counter will decrement to 4. However, you don’t know whether it was the box with ID of 4 that was removed, so you cannot assume that you can reuse that number to create a new box – you will be creating duplicates every time you remove a box which is not last.

    I would suggest simply having another variable to keep track of the next ID to use (to keep them unique) and increment that variable every time you add a box, and then using counter only to keep track of the number of boxes on the screen.

    Code:

    const hob = document.getElementById("hob");
    let counter = 0;
    let nextId = 1;
    
    function addBox() {
        if(counter < 10) {
            const div = document.createElement("div");
            div.setAttribute("class", "form-group");
            div.setAttribute("id", "box_" + nextId);
            
            const boxHtml = "<input class='mybox' type='button' value='-' onClick='removeBox(this)' /><label>İçerik</label><input type='text' name='ProductFeature.Feature"+counter+"' class='myinput form-control myinput' id='ProductFeature.Feature"+counter+"'>";
            div.innerHTML = boxHtml;
            
            hob.appendChild(div);
            counter++;
            nextId++;
        }
    }
    
    function removeBox(ele) {
        counter--;
        ele.parentNode.remove();
    }
    

    If you really wanted to always fill the ID gaps (although I feel like it doesn’t make sense, as the ID will not represent the position of the box anyway, you would have boxes ordered like 1, 4, 2, 3), then you would need to keep track of removed IDs and reuse them in the correct order when creating a box. To achieve that, you would need to adjust the removeBox function to additionally take an ID parameter, provide that ID in the onClick attribute of the button, store that ID in some array, and then take the smallest available ID value from that array when creating a box (if there is such an ID, otherwise just use counter + 1).

    That would look something like this:

    const idQueue = [];
    const hob = document.getElementById("hob");
    let counter = 0;
    
    function addBox() {
        if(counter < 10) {
            const div = document.createElement("div");
            const boxId = idQueue.length === 0 ? counter + 1 : idQueue.shift();
            div.setAttribute("class", "form-group");
            div.setAttribute("id", "box_" + boxId);
            
            const boxHtml = "<input class='mybox' type='button' value='-' onClick='removeBox(this, "+boxId+")' /><label>İçerik</label><input type='text' name='ProductFeature.Feature"+counter+"' class='myinput form-control myinput' id='ProductFeature.Feature"+counter+"'>";
            div.innerHTML = boxHtml;
            
            hob.appendChild(div);
            counter++;
        }
    }
    
    function removeBox(ele, boxId) {
        counter--;
        
        // find the index at which to insert the ID to keep the queue sorted
        let queueIndex = idQueue.findIndex(id => id > boxId);
        if(queueIndex === -1) {
            queueIndex = idQueue.length;
        }
        
        // insert the ID at that position
        idQueue.splice(queueIndex, 0, boxId);
        
        ele.parentNode.remove();
    }
    

    However, as mentioned, I do not see any viable reason to do this, and suggest going with the first approach instead.

    Login or Signup to reply.
  3. Here is a whole working demo you could follow:

    <button type="button" onclick="addBox()">Add</button>
    <div id="hob">
    
    </div>
    @section Scripts
    {
        <script>
            let textBox = "";
            let hob = document.getElementById("hob")
            function addBox()
            {
                var counter = $("div[id^='box_']").length +1 ;
                if (counter<10)
                {                
                    let div = document.createElement("div");
                    div.setAttribute("class","form-group");
                    div.setAttribute("id","box_"+counter);                
                    let textBox = "<input class='mybox' type='button' value='-' onclick='removeBox(this)'><label> İçerik</label><input type='text' name='ProductFeature.Feature"+counter+"' class='myinput form-control myinput' id='ProductFeature.Feature"+counter+"'>";                
                    div.innerHTML = textBox;               
                    hob.appendChild(div);
                }
            }
            function removeBox(ele)
            {
                $(ele).closest("div[id^='box_']").remove();
                $("div[id^='box_']").each(function(i){
                $(this).attr('id',"box_" + (i+1));       
                })
            }      
        </script>
    }
    

    Result:

    enter image description here

    Update:

    It seems you also want to make model binding works. Not sure how is your model, here is a simple demo:

    public class ProductFeature
    {
        public string Feature { get; set; }
    }
    

    If your action wants to receive List<ProductFeature> product, your frontend input name should be like:product[index].Feature.

    And modify your js code for how to define textbox like below:

    1.the index of the Array start with 0;

    2.Model Binding binds the model by name, actually id does not influence the model binding, anyway I also change it to meet your requirement.

    let textbox = "<input class='mybox' type='button' value='-' onclick='removeBox(this)'><label> İçerik</label><input type='text' name='product["+(counter-1)+"].Feature' class='myinput form-control myinput' id='product["+(counter-1)+"].Feature'>"; 
    

    Result:

    enter image description here

    Update2:

    @section Scripts
    {
        <script>
            let textBox = "";
            let hob = document.getElementById("hob")
            function addBox()
            {
                var counter = $("div[id^='box_']").length +1 ;
                if (counter<10)
                {                
                    let div = document.createElement("div");
                    div.setAttribute("class","form-group");
                    div.setAttribute("id","box_"+counter);                
                    let textBox = "<input class='mybox' type='button' value='-' onclick='removeBox(this)'><label> İçerik</label><input type='text' name='product["+(counter-1)+"].Feature' class='myinput form-control myinput' id='product["+(counter-1)+"].Feature'>";  
                    div.innerHTML = textBox;               
                    hob.appendChild(div);
                }
            }
            function removeBox(ele)
            {
                $(ele).closest("div[id^='box_']").remove();
                $("div[id^='box_']").each(function(i){
                    $(this).attr('id',"box_" + (i+1));       
                })
                //add this..........
                $("input[id$='Feature']").each(function(i) {
                    $(this).attr('id', "product[" + i  +"].Feature");       
                    $(this).attr('name', "product[" + i +"].Feature");       
                })
            }      
        </script>
    }
    
    Login or Signup to reply.
  4. I’ve done this counter problem and it’s more headache than anything
    If you’re only using the counter to Add+Remove the boxes, I say to just scrap it and instead wrap each on in a div… That way you can do $('.mybox').parent().remove(); and remove it easily

    HTML end goal
    <div class="formwrapper">
        <input class='mybox' type='button' value='-'>
        <label> İçerik</label>
        <input type='text' name='ProductFeature.Feature' class='myinput form-control'>
    </div>
    
    
    Remove Function
    // remove element
    $('.mybox').click(function(){
        $(this).parent().remove();
    });
    
    Fetching Data
    $.each($('.formwrapper'), function(counter, wrapper){
        // counter = you have the number of the row
    
        // input = you have the input
        input = $(wrapper).find('.myinput');
    
        // input value
        value = input.val();
    
        // creating original ID ( but you have the ID + Value, so you shouldn't need it)
        id = 'ProductFeature.Feature'+counter;
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search