如何使用Bootstrap的预先输入功能创建jquery可编辑表

时间:2014-07-04 22:23:23

标签: jquery twitter-bootstrap autofill typeahead

我有两个单独运作良好的功能。第一个使用Bootstrap的预先输入功能。第二个允许HTML表格单元格可编辑,而无需进行提交或页面刷新。我想要做的就是将两者合并而不是为它编写一个全新的功能。例如:当用户双击表格单元格时,我希望文本框是预先输入的,这样当他开始输入条目时,有效条目将开始显示在下面的菜单中。一旦用户做出选择,当焦点丢失时,底层数据库表将正常更新。

我以为我可以像这样添加一个“可编辑”的事件:

cell.on('keydown', function() {$(".autofill").typeahead();});

但是没有运气:-(。有什么建议吗?下面是两个函数的代码.... 顺便说一下,我正在使用Bootstrap 2.1.1和Jquery 1.8.3

$(document).ready(function(){

/************************************************************
              USING BOOTSTRAP'S TYPEAHEAD 
************************************************************/
$('.autofill').typeahead({
  source: function (query, process) {
    query = $(".autofill").val();
    link = 'ajax/gdata.aspx';
    sp = $(".autofill").attr("proc");
    src = $(".autofill").attr("src");
    if(!src) src = "No Source";

        $.get(link, {desc:query}, function(data) {
          var x = $.parseJSON(data);
          codes = [];
          map = {}; 
          $.each(x, function(i, cd) {
            map[cd.code_desc] = cd;
            codes.push(cd.code_desc);
            process(codes);
          });
        });
  },

  matcher: function(item) {
    if (item.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1) { 
      return true;
    }
  },

  sorter: function(items) {
    return items.sort();
  },

  highlighter: function(item) {
    var regex = new RegExp( '(' + this.query + ')', 'gi' );
    return item.replace( regex, "<b>$1</b>" );
  },

  updater: function(item) {
    d = $(".autofill").attr("show");
    selectedItem = map[item].code;
    if (d == 0) {
      return selectedItem;  //return code
    } else {
      return item;      //return description
    }
  }
});


/************************************************************
  Edit underlying table's column directly from HTML table.
        An editable field is highlighted in yellow
************************************************************/
$(".editable").dblclick(function() {
  var a = $.url().param("type");
  var b = $.url().param("id");
  var c = $.url().param("grpid");
  var d = $("input[name='step']").val();
  var e = $(this).attr("data-cap");
  var f = $(this).attr("data-ihtml");
  var m = "table";
  var warn = "#warn" + d;
  var id = $(this).attr("data-id");
  var type = $(this).attr("data-rec");
  var db = "MyDB";
  var tab = a + b + '_' + type;
  var column = $(this).attr("data-col");
  var idcol = $(this).attr("data-idcol");
  var idcolval = $(this).attr("data-idcolval");
  var cell = $(this);
  var cellWidth = cell.attr("width");
  var prevContent = cell.text();
  var URL = "ajax/p.aspx";
  var et = $(this).attr("entry-type");
  var s = $(this).attr("show");
  var src = $(this).attr("src");

  if(!src) {
    src = '""';
  }

  if(!s) {
    s = "1";
  }

  if(!e) {
    e = "Y";
  }

  if(!et) {
    et = "";
  }

  if(!f) {
    if(et == "") var f = '<input type="text" name="newValue" size="4" value="' + prevContent + '" id="txt' + id + '" />';
    if(et == "autofill") var f = '<input type="text" data-provide="typeahead" class="autofill" autocomplete="off" proc="1" show="' + s + '" name="newValue" size="4" value="' + prevContent + '" id="txt' + id + '" />';
  }

  var form = '<form action = "javascript: this.preventDefault">' + f + '</form>';
  var msg = "Changes will take effect immediately after moving off this cell!";

  $(warn).html('');
  $(warn).append('<div class="alert alert-warning">' + msg  + '</div>');
  cell.html(form).find('input[type=text]').focus().select().attr('width', cellWidth);
  cell.on('click', function() {return false;});
  cell.focusout(function() {
    var newContent = $("#txt" + id).val();
    var newVal = newContent;
    var g = f.slice(f.search("select"), 7);
    if (g == "select") {
      var h = "#txt" + id + " option:selected";
      newContent = $(h).text();
    }
    if (newContent == "") {
      cell.text(prevContent);
      return false;
    }
    if (newContent == prevContent) {
      cell.text(prevContent);
      return false;
    }

    if (e == "Y") {
      newVal = newVal.toUpperCase();
      newContent = newContent.toUpperCase();
    }

    var formData = 'type=' + a + '&id=' + b + '&grpid=' + c + '&modal=' + m + '&db=' + db + '&tab=' + tab + '&col=' + column + '&val=' + newVal + '&idcol=' + idcol + '&idcolval=' + idcolval + '&orig=' + prevContent + '&cap=' + e;

    $.ajax({
      url   : URL,
      type  : "POST",
      data  : formData,
      dataType  : "html"
    })
      .done(function(msg) {
    //console.log(msg);

    if(!msg) {
      $(warn).html('');
      $(warn).append('<div class="alert alert-success">' + "Record successfully updated!" + '</div>');
          //location.reload(true);
      cell.text(newContent);
    } else {
      $(warn).html('');
      $(warn).append('<div class="alert alert-error">' + msg + '</div>');
      cell.text(prevContent);
    }
    }); 
  });   
});

});

1 个答案:

答案 0 :(得分:0)

回答我自己的问题并不好玩,但我想我可以帮助别人在一个很少涉及的话题上节省数小时的挫败感。所以我提出了一个解决方案,就像一个已经生产了两周的冠军,没有任何问题!首先反转执行顺序:首先启用typeahead,然后在更改时自动更新字段。其次,在DOM中添加隐藏字段以存储启用typeahead的文本框的键值。最后,将两个过程更改为以下函数:getData(e)和updateNow(e),可以在运行时调用。在使用其值更新数据库之前,自动更新功能UpdateNow(e)将查找对隐藏字段(而不是支持typeahead的文本框)的更改。添加了附加数据属性以增强功能和通用可重用性,例如要求状态值列表取决于所选的国家/地区代码。这是修改后的代码:

/************************************************************
              USING BOOTSTRAP'S TYPEAHEAD 
************************************************************/
getData("#auto_idst");
getData("#auto_idctry");


function getData(elem) {
$(elem).typeahead({
  source: function (query, process) {
    var query = $(elem).val();
    var link = 'ajax/gdata.aspx';
    data_fld = $(elem).attr("data-fld");
    var src = $(elem).attr("src");
    var dependence = $(elem).attr("data-slave");
    if(!dependence) {dependence = "";}
    var ctry = $("#" + dependence).val();
    if(!ctry) {ctry = "";}
    if(!src) var src = 0;
    if(src == '3') {link = 'ajax/gdata.aspx?c=' + ctry;}

    $.get(link, {desc:query, src:src}, function(data) {
      var x = $.parseJSON(data);
      codes = [];
      map = {}; 
      $.each(x, function(i, cd) {
        map[cd.code_desc] = cd;
        codes.push(cd.code_desc);
        process(codes);
      });
    });
  },

  matcher: function(item) {
    if (item.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1) { 
      return true;
    }
  },

  sorter: function(items) {
    return items.sort();
  },

  highlighter: function(item) {
    var regex = new RegExp( '(' + this.query + ')', 'gi' );
    return item.replace( regex, "<b>$1</b>" );
  },

  updater: function(item) {
    d = $(elem).attr("show");
    selectedItem = map[item].code;

    if (d == 0) {
      $("#" + data_fld).val(selectedItem);
      $("#" + data_fld).trigger("change");
      return selectedItem;  //return code
    } else {
      $("#" + data_fld).val(item);
      $("#" + data_fld).trigger("change");
      return item;      //return description
    }
  }
});
};


/************************************************************
  Edit underlying table's column directly from HTML table.
************************************************************/

$(".now").on("change", function() {
 if ($(this).is(":checkbox")) {
    var id = $(this).attr("id");
    id = "#" + id;
  } else {
    var id = $(this).attr("data-id");
    id = "#" + id;
  }

  updateNow($(id));
});



$(this).on("focusout", function() {
  var val = $(this).val();
  val = $.trim(val);

  if (val == "") {
    var c = $(".now").val();
    $(this).val(c);
  }
});


function updateNow(e) {
  var t = e.attr("data-rec");
  var p = e.attr("data-fld");
  var warn = "#stat_" + p;
  var type = $.url().param("type");
  var id = $.url().param("id");
  var grpid = $.url().param("grpid");
  var db = e.attr("data-db");
  var tab = type + id + '_' + t;
  var col = e.attr("data-col");
  var idcol = e.attr("data-idcol");
  var idcolval = e.attr("data-idcolval");
  var oldval = e.attr("data-oldval");
  var URL = "ajax/p.aspx";
  var m = "table";

/*======================================================
  First find out if element is a checkbox.  If so, find
  out if it's checked.  If so, set newval to it's value;
  otherwise, set it to blank.
========================================================*/
   if (e.is(":checkbox")) {
    var chk = e.is(":checked");
    if (chk == "1") {
      var newval = e.val();
    } else {
      var newval = "";
      var control = "#" + e.attr("data-master");
      if (!control) {
        control = "";
      } else {
        $(control).attr("data-oldval", newval);
      }
    }
  } else if (e.is("select")) {
    var newval = "";
    var mm = $("#" + p + "_mm").val();
    var dd = $("#" + p + "_dd").val();
    var yy = $("#" + p + "_yy").val();
    var omm = $("#" + p + "_mm").attr("data-oldval");
    var odd = $("#" + p + "_dd").attr("data-oldval");
    var oyy = $("#" + p + "_yy").attr("data-oldval");

    if ((!mm) || (!dd) || (!yy)) {
      var newval = $("#" + p).val();
    }
    else {
      var sel_dt = 1;
      newval = mm + dd + yy;
      oldval = omm + odd + oyy;
    }
  } else {
      var newval = $("#" + p).val();
  }


  newval = newval.toUpperCase();
  var formData = 'type=' + type + '&id=' + id + '&grpid=' + grpid + '&modal=' + m + '&db=' + db + '&tab=' + tab + '&col=' + col + '&idcol=' + idcol + '&idcolval=' + idcolval + '&val=' + newval + '&orig=' + oldval;
  if((!db) || (!idcol) || (!idcolval)) return false;     

  $.ajax({
    url     : URL,
    type    : "POST",
    data    : formData,
    dataType    : "html"
  })
    .done(function(msg) {
    //console.log(msg);
    if(!msg) {
      $(warn).html('');
      var i = '<img src="assets/images/icon-good.png" />';
      $(warn).html(i);
      e.attr("data-oldval", newval);
      if (sel_dt == 1) {
        $("#" + p + "_mm").val(mm);
        $("#" + p + "_dd").val(dd);
        $("#" + p + "_yy").val(yy);
      } else { 
        e.val(newval); 
      }
    }
    else {
      $(warn).html('');
      var i = '<a href="#" title="' + msg + '"><img src="assets/images/icon-bad.png" /></a>';
      if (sel_dt == 1) {
        $("#" + p + "_mm").val(omm);
        $("#" + p + "_dd").val(odd);
        $("#" + p + "_yy").val(oyy);
      } else { 
        e.val(oldval);
      }
      $(warn).html(i);
    }
    }); 
};

你的DOM表应该有类似的东西:

<td><span id="stat_idctry"></span> ID Issuing Country:</td><td><input name="f4A_idctry" type="text" id="auto_idctry" class="autofill input-large" data-provide="typeahead" autocomplete="off" maxlength="50" data-db="1" data-col="id_iss_ctry" data-idcol="seq" data-idcolval="1" data-rec="4A" data-fld="idctry" data-oldval="" show="0" src="1" value="" /><input type="hidden" name="h_idctry" id="idctry" data-id="auto_idctry" class="now" value="" /></td>
<td><span id="stat_idst"></span> ID Issuing State:</td><td><input name="f4A_idst" type="text" id="auto_idst" class="autofill input-mini" data-provide="typeahead" autocomplete="off" maxlength="15" data-db="1" data-col="id_iss_st" data-oldval="" data-idcol="seq" data-idcolval="1" data-rec="4A" data-fld="idst" show="0" src="3" data-slave="idctry" value="" /><input type="hidden" name="h_idst" id="idst" data-id="auto_idst" class="now" value="" /></td>

关于此处使用的数据属性的一些注释。对于使用上面的getData(e)函数工作的typeahead,你必须使用class =&#34; autofill&#34;,data-provide =&#34; typeahead&#34;,src必须有一个值。在我的实现中,src属性用作后端存储过程的参数,该存储过程将所需数据提取到文本框中。这样做,允许我对多种类型的文本框使用一个存储过程,并使用相同的ajax URL链接。设置自动完成=&#34;关闭&#34;阻止现代浏览器在用户键入值时使用以前使用的值自动填充文本框。设置show =&#34; 0&#34;强制文本框显示键值而不是显示的描述。 &#34; 0&#34;以外的值for show将在文本框中显示所选的描述,为我提供一定程度的灵活性,以便我需要代码而不是描述。 typeahead使用data-slave属性来设置附加参数,以根据data-slave属性指示的文本框中的值在依赖文本框中获取正确的数据。

对于自动更新,您必须将隐藏字段的类设置为&#34; now&#34;并且data-id为更新其值的typeahead文本框的相同ID。这允许自动更新功能查看先行文本框中的其他关键数据属性,例如:data-db,data-col,data-idcol,data-idcolval和data-rec。是的,我可以将其他数据属性添加到隐藏字段,但这需要我必须将必要的数据属性剪切并粘贴到原始文本框的隐藏字段中。您可以这样做,但如果这样做,请确保将此代码更改为:

$(".now").on("change", function() {
 if ($(this).is(":checkbox")) {
    var id = $(this).attr("id");
    id = "#" + id;
  } else {
    var id = $(this).attr("id");
    id = "#" + id;
  }

  updateNow($(id));
});