Home  >  Article  >  Web Front-end  >  Bootstrap style data two-way binding of single-select and multi-select drop-down boxes implemented by custom Angular instructions and jQuery_AngularJS

Bootstrap style data two-way binding of single-select and multi-select drop-down boxes implemented by custom Angular instructions and jQuery_AngularJS

WBOY
WBOYOriginal
2016-05-16 15:26:141901browse

Let’s talk a little bit about it first. People who are familiar with Angular will like this plug-in.

00. Putting the cart before the horse

I have to admit that I am a person who likes to put the cart before the horse. When I was a student, I liked to do the late homework first, leave the homework due soon, and then slowly finish the unimportant homework. Damn it. XX homework is due soon, so hurry up and make up for it. Now I'm working on this project, because I couldn't find a suitable multi-select drop-down Web plug-in, and I didn't want to use the ugly 83e93235161a78387dfc0b11c4aaaabd18bb6ffaf0152bbe49cd8a3620346341 that comes with HTML, so I spent a whole day making one. Perhaps the time taken up in the development of main functions in this way will make development more urgent. I feel like a programmer with masochistic tendencies and obsessive-compulsive disorder in css and code indentation.

01. Superfluous

Angular’s ​​powerful controller seems to be able to meet most UI needs, but NodeJS applications often use template engines such as ejs and jade to dynamically generate html pages. Then the problem arises. When I want to pass the background What should I do if the parameters of res.render() in express are directly displayed on the interface and bound to the corresponding ng-model?

Solution 1: Don’t do everything all at once. Angular’s ​​Controller can just send a post request and then get the data.

Solution 2, first use the template to temporarily store it on the html, and then let the Controller initialize the value of $scope based on the data on the page

Solution 3. I have little knowledge of Angular and EJS. Can anyone teach me a good way?

For example, now I want to make a selection drop-down box 221f08282418e2996498697df914ce4en5a07473c87748fb1bf73f23d45547ab8xx4afa15d3069109ac30911f04c56f333818bb6ffaf0152bbe49cd8a3620346341. The options are in the background. I don’t want to post them separately, nor do I want to put them on the page. The Controller writes logic processing separately, and the Angular community has a ui-select plug-in. It seems that the data is taken from $scope, not directly from the 1c2eebcbc344187d3ddb16708e916941 tag. I was very popular at that time, not just one Drop down box, do it yourself.

10. Optimistic programmers

The idea is very clear, define an Angular directive -> Take out the option value -> Add various events -> scope data binding -> Finished
I estimated the time to be half a day, but I can only guess how long it actually took. I have obsessive-compulsive css, a poor understanding of Angular (so many HTML operations still use jQuery), and insufficient consideration of events, which ultimately took more than twice the time. Finished,
No more nonsense, it is simple and practical. You can either bind ng-model $scope.xxx on the fly, or you can directly adjust jQuery's $("label's id").val() to get the value,
Git portal duang: https://git.oschina.net/code2life/easy-select.git
Demo portal duang~duang: http://ydxxwb.sinaapp.com/easy-select-demo/ (The code is not the latest, there are two bug fixes that have not been deployed yet)

11. Grading

1. How to use: Introduce the library file Bootstrap, Angular1.x, introduce the style.css file (you can modify the css to customize the style you want), easy-select.js, define Angular's Controller, and rely on the easySelect module. Like this↓
angular.module('dataDisplay', ['easySelect']).controller('selectController', ['$scope', '$http',function ($scope, $http) { // your code }]);

Then just refer to the specification of the demo example to define the selection box. Isn’t it very familiar with the native HTML select tag?

2. Source code explanation: DOM operations and events are implemented with jQuery, and each step has simple comments. The key to achieving two-way binding is to obtain the ng-model defined on the tag, and then set the scope in the event[ ng-model] value,
And call the $digest() loop to let Angular update the DOM according to ng-model. $digest is one of the cores of Angular's two-way binding. The principle is to synchronize the changed scope value to all places that need to be updated. The implementation is not yet big. I understand, I will study these things starting with $, $$ in Angular when I have time.

3. Adaptive and css, Bootstrap is adaptive, css can be customized with different styles, style.css has relevant comments

easy-select.js

var comDirective = angular.module('easySelect', []);
comDirective.directive("easySelect", function () {
 return {
  link: function (scope, element, attrs) {
   var ngModel = $(element).attr("ng-model");
   if(!ngModel || ngModel.length == 0) {
    ngModel = "defaultSelectModel";
   }
   var status = false; //toggle boolean
   var valueMap = "";
   var options = $(element).children();
   $(element).attr("style", "padding:0");
   //hide original options
   $.each(options, function (opt) {
    $(options[opt]).attr("style", "display:none");
   });
   //build ul
   var html = "<div id='" + attrs.id + "-root' style='width:100%;position: relative;left:-1px'>" +
    "<p id='display-"+attrs.id + "' style='padding:6px 12px "+ ((attrs.multiple != undefined)&#63;"4px":"7px")+
    " 12px;margin:0;border:none;width:95%;margin-left:2px;background-color: transparent'>" +
    "<span style='display: inline-block;padding-bottom: 3px'> </span></p>" + //this is a dummy span
    "<ul id='" + attrs.id +
    "-container' class='list-group easy-select-container' style='display:none'>"; //options' container
   if(attrs.multiple != undefined) {
    $.each(options, function (opt) {
     html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+
     attrs.id+ "'><div style='width:100%;display:inline-block'>" + $(options[opt]).html() +
     "</div><span value='"+ $(options[opt]).val() +"' class='my-li-option glyphicon glyphicon-ok'></span></li>";
    });
   } else {
    $.each(options, function (opt) {
     if($(options[opt]).attr("default") != undefined) {
      scope[ngModel] = $(options[opt]).val();
      valueMap = $(options[opt]).html();
      html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+ attrs.id+ "'>"
      + $(options[opt]).html() + "</li>";
     } else {
      html += "<li value='"+ $(options[opt]).val() +"' class='my-li-container list-group-item option-"+ attrs.id+ "'>"
      + $(options[opt]).html() + "</li>";
     }
    });
   }
   //if multiple, add button
   if (attrs.multiple != undefined) {
    html += "<li class='list-group-item ' for='ensure-li'><button class='btn btn-default'" +
    " for='ensure-btn' style='padding: 2px' > 确定 </button></li>";
   }
   //render ui
   html += "</ul></div>";
   $(element).append(html);
   $(".my-li-option").each(function(){
    $(this).fadeOut(0);
   });
   if(attrs.multiple == undefined)
    $($("#display-"+attrs.id).children()[0]).html(valueMap);
   //adjust width
   $("#" + attrs.id + "-root").width($("#" + attrs.id + "-root").width() + 2);
   //mouse leave event
   $(element).mouseleave(function(){
    $(".my-li-container").each(function(){
     $(this).attr("style","");
    });
    if(status) {
     $("#" + attrs.id + "-container").attr("style", "display:none");
     status = !status;
    }
   });
   //multiple select seems complex
   if (attrs.multiple != undefined) {
    //click event
    $(element).click(function (e) {
     //if click on tags, remove it
     if($(e.target).attr("for") == "option-tag") {
      // change val and digest change item in angular
      scope[ngModel] = $(element).val().replace($(e.target).attr("value"),"").replace(/;+/,";").replace(/^;/,"");
      $(element).val(scope[ngModel]);
      scope.$digest();
      $(e.target).remove();
      $(".my-li-option").each(function(){
       if($(this).attr("value") == $(e.target).attr("value")) {
        $(this).css("opacity","0.01");
       }
      });
     } else if($(this).attr("for") != 'ensure-li') {
      //toggle ul
      $("#" + attrs.id + "-container").attr("style", status &#63; "display:none" : "");
      status = !status;
     }
    });
    $(".option-"+attrs.id).each(function(){
     $(this).on('click',function(){
      var selectValue = $(element).val();
      var currentValue = $(this).attr("value");
      var selected = false;
      //if option is selected ,remove it
      var temp = selectValue.split(";");
      $.each(temp,function(obj){
       if(temp[obj].indexOf(currentValue) != -1) {
        selected = true;
       }
      })
      if(selected) {
       $($(this).children()[1]).fadeTo(300,0.01);
       scope[ngModel] = $(element).val().replace(currentValue,"").replace(/;{2}/,";").replace(/^;/,"");
       $(element).val(scope[ngModel]);
       scope.$digest();
       $("#display-"+attrs.id + " span").each(function(){
        if($(this).attr("value") == currentValue) {
         $(this).remove();
        }
       });
      } else {
       //add option to val() and ui
       $($(this).children()[1]).fadeTo(300,1);
       scope[ngModel] = ($(element).val()+";"+currentValue).replace(/;{2}/,";").replace(/^;/,"");
       $(element).val(scope[ngModel]);
       scope.$digest();
       $("#display-"+attrs.id).append(
        "<span for='option-tag' value='"+ $(this).attr("value") +"' class='p-option-tag'>"
        +$(this).children()[0].innerHTML+ "</span>");
      }
      status = !status; // prevent bubble
     });
     //control background
     $(this).mouseenter(function(){
      $(".my-li-container").each(function(){
       $(this).attr("style","");
      });
      $(this).attr("style","background-color:#eee");
     });
    });
   } else {
    $(".option-"+attrs.id).each(function(){
     $(this).mouseenter(function(){
      $(".my-li-container").each(function(){
       $(this).attr("style","");
      });
      $(this).attr("style","background-color:#eee");
     });
    });
    //single select ,just add value and remove ul
    $(element).click(function () {
     $("#" + attrs.id + "-container").attr("style", status &#63; "display:none" : "");
     status = !status;
    });
    $(".option-"+attrs.id).each(function(){
     $(this).on('click',function(){
      scope[ngModel] = $(this).attr("value");
      $(element).val(scope[ngModel]);
      scope.$digest();
      console.log(ngModel);
      console.log(element.val());
      $($("#display-"+attrs.id).children()[0]).html($(this).html());
     });
    });
   }
  }
 }
}); 

100. If you see this, it means you are interested in this little thing. Let’s improve it together on git. The two functions of customizing option templates and option grouping have not been implemented yet. Young man, join the open source army.

The above is the single-select and multi-select drop-down boxes that the editor shared with you with custom Angular instructions and Bootstrap style data two-way binding implemented by jQuery. I hope you like it.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn