bootstrap-select with custom buttons & add new values on the fly [closed]
Asked Answered
S

2

26

enter image description herei needed to use a dropdown list that could do that functionality:

  1. dynamically fetches and loads values from the database
  2. has an embeded search box
  3. has 2 custom buttons on each Li, one for delete and one for edit.
  4. the search field, if the searched text does not exist, add it on 'enter' press, either on the same select <option> and also on the database with Ajax.

I chose the custom select for @twitter bootstrap 'bootstrap-select' from silviomoreto git repository and because I did not find the functionality that I want i tried to make it on my own.

So, for those that need or would like to add that functionality on their web-apps , I wrote down my solution, which is not the best solution but it works, and I am open to any suggestions to make it work better.

1. step: create a selectpicker with parameters : data-size="5" (show 5 values and the add scrollbar), data-live-search="true" (add the search box on the top) and load the values that I get from db (preferably with ajax):

       <select class="selectpicker typedropdown" data-size="5" data-live-search="true">
                            <?php
                            $counter=0;
                            foreach($eventTypeList as $evType){
                                $counter++;
                                if(is_array($evType)){
                                    echo "<option>".$evType['type_name']."</option>";
                                }else{
                                    echo "<option>".$evType."</option>";
                                }

                            } ?>
                        </select>

2. step: add the custom buttons (edit, delete) (override the prototype function 'createLi')

override the prototype function 'createLi' on your main js file like this:

  $.fn.selectpicker.Constructor.prototype.createLi = function (){..}

Inside :

var generateLI = function (content, index, classes, optgroup) {
        return '<li' + ........

just before the 'return' add the line with tha two button classes :

content += "<div class='removeTypebtn'></div><div class='editTypebtn'></div>";

so that , when you create the li items you also create the two custom buttons on each row.

3. step: catch 'click' events for edit & delete value (also makes an ajax request on the database to update the dbtable)

$(document.body).on('click','.btn-group.typedropdown .dropdown-menu ul li .removeTypebtn',function(event){
        var index = $(event.target).closest( "li" ).data('original-index');//get the item index
        var type_name = $(event.target).closest( "li" ).text();
        deleteType(index,type_name);
    });

in a similar way we catch the 'click' event for the 'edit item', so I omitted it.

now we need to do the interesting part , to delete the selected item from the selectpicker and also make an ajax request to delete it from dbtable. the database is beyond the tutorial scope so , I left it out. pay attention inside the success function how I remove.

function deleteType(index,type_name){
        var url = "<?php echo $domain.$deleteType; ?>";
        data = {'index':index,'type_name':type_name};
        $.ajax({
            cache: false,
            url : url,
            type: "POST",
            data : data,
            success : function(data, textStatus, jqXHR){
                $('.typedropdown').find('[data-original-index=$index]').remove();//remove selected item from selectpicker
            $('.typedropdown').find('option:contains($type_name)').remove();";// remove value also from the hidden select
                $('.selectpicker.typedropdown').selectpicker('val', []);//clear selected
            },
            error : function(xhr, ajaxOptions, thrownError){
                alert(thrownError);
            }
        });
    }

4. step: create the 'add new value' functionality on Enter (as you know the search field only permit searches inside the li's)

so, when we init the selectpicker component , we change the 'noneResultsText' message , by altering the parameter : noneResultsText :

//init selectpicker
    selectPickerType = $('.selectpicker.typedropdown').selectpicker({
        noneResultsText:'Add new {0}',
        selectOnTab: true
    });

so, now whenever we write down a new word that does not exist , we get the message Add new 'myword'

Now we need to catch the click event.

$('.selectpicker.typedropdown').data('selectpicker').$searchbox.on('keydown',function(e){
            if(e.keyCode == 13){
                addNewDropdownValue(e.target.value,'type');
                return false;
            }
        });

and the addNewDropdownValue function : (with an ajax request to dbtable to add the new value) (pay attention into the success function)

function addNewDropdownValue(newValue,tble){
    var url = "<?php echo $domain.$addDropdownValueURL; ?>";
    data = {'newValue':newValue,'tble':tble};
    var loading = $('.loading');
    $.ajax({
        cache: false,
        url : url,
        type: "POST",
        data : data,
        beforeSend: function( xhr ) {
            loading.css('top',screen.height/2);
            loading.css('left',screen.width/2);
            loading.html('<div><img alt="loading..." src="<?php echo $domain; ?>/assets/images/loader/ajax_loader_blue_48.gif" /></div>').show();
        },
        success : function(data, textStatus, jqXHR){
            loading.fadeOut(500);
            $('.selectpicker.".$tble."dropdown').append('<option selected>$newValue</option>');//append new item on the selectpicker
            $('.selectpicker.".$tble."dropdown').val('$newValue');//select the new value
            $('.selectpicker.".$tble."dropdown').selectpicker('refresh');//refresh the selectpicker
            $('.".$tble."dropdown').removeClass('open');//close the selectpicker
        },
        error : function(xhr, ajaxOptions, thrownError){
            alert(thrownError);
        }
    });
}

that's it , now we have a custom bootstrap select-picker with delete and edit buttons on each row and add new text functionality on enter.

please by any means, tell me your opinion on how we can make it work better or if you have any questions.

Stressful answered 10/7, 2015 at 7:50 Comment(6)
"please by any means, tell me your opinion on how we can make it work better ..." - is this your question? If so, code reviews are off topic for SO. See http://codereview.stackexchange.com/Protolanguage
of course not, this is a small guide/tutorial on how you can make that custom component work in that way!!Stressful
This is a q&a site, not a tutorial/code repository I'm afraidProtolanguage
I'm voting to close this question as off-topic because it is not a questionProtolanguage
@TheoItzaris This is a nice workaround although is there a way to add the custom value when the user clicks on noneResultsText in addition to pressing the enter key?Handsaw
@theo have you placed this in a repo anywhere? i think the question may be closed and may have a need for this laterArtist
C
0

How this could be done better is to remove PHP from the equation. In fact, remove any server side code from generating html or DOM elements. This will leave you with two pieces, the javascript to render the UI and the database methods via an API (node.js or the like).

The implementation would look something like the following -

$.ajax({
  url: "/api/databaseCall/",
  success: function(data){

/* 
Build DropDown
the data variable will be a hash or array of returned db results
iterate over them and build UI
*/

    for(var i=0; i < data.results.length; i++){

      var row = '<option id=' + data.results[i].id + '>' + data.results[i].value + '</option>';
      $(".dropdown").append(row);
    } 

  }
});

Angular, react, backbone all are built with this approach in mind. The only one I endorse at this time is backbone.js. Backbone is very easy to learn.

Once you build the UI programmatically with javascript any functionality will be bound automatically using a framework like backbone.

Caa answered 5/1, 2017 at 17:50 Comment(0)
L
0

You can make it work better by forgetting about that PHP up top that actually starts this whole thing.

Suppose you had a javascript function that will ajax to the server and get the values instead of that PHP code. We will call it function fetchData()

fetchData() will get the values from the database, empty the select if it has any values, and put the new values in the select. Then, you will continue to attach your events. (edit, delete, etc...)

now on document ready fetchData();

on delete, run the delete function, then, fetchData();

on update, run the update function, then, fetchData();

on any event you can think of, run the event function, then fetchData();

The beauty of this method is that you don't have to manually update your elements when you delete or update. Plus you are always getting new records from the database every time you fetchData().

Imagine there are 10 different users updating records on 10 different computers. with the old way as a user, I wouldn't see what the other users updated until I refresh the page. but now I can see that every time I interact with the page because it will fetch from the database and get all the records.

you can even take it a step further and say every 30 seconds fetchData(); so I'm always being updated with the new information even when I don't interact with the page.

This makes your code clean. You will only have to worry about a handful of events after you write this function, and you don't have to worry about what happens after the events, on the screen of the users, because you always call fetchData() and you're done. Instead of removing an option when they delete it or update text and value for an option when they update it etc..etc...

Ludhiana answered 21/7, 2017 at 23:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.