Hola, hoy continuando con jquery vamos a desarrollar un pequeño control, el objetivo de este control es preseleccionar las etiquetas existentes mostradas en la caja de texto, si es que están registradas, en caso contrario solo las muestra en el textbox y también implementaremos un método para registrar las etiquetas no existentes en el data store… por un desgaste de neuronas
se me ocurrió ponerle por nombre TagControl.
Bueno ya es suficiente de palabras vamos a la implementación:
Primero que nada permítanme decirles que implementaremos esto en un control de usuario, y ahora continuando, el código html siguiente nos ayudara a generar la interfaz del control.
<div style="position:relative;">
<asp:TextBox runat="server" ID="txtEtiquetas" Width="295"></asp:TextBox>
<a href="javascript:void(0);" id="mostrar">Show selector</a>
<a href="javascript:void(0);" id="limpiar">
Limpiar</a><br />
<span style="font-size: 10px;">Las etiquetas deben estar separadas
por una coma</span>
<div id="panTags" class="wrapper" runat="server">
<div id="wrapperShowSelector">
<div class="headerSelector">
<span class="titleSelector">Show selector</span>
<br style="clear: both;" />
</div>
<div class="contentSelector">
<div id="tagsList" runat="server">
</div>
<p runat="server" id="phTags">
</p>
</div>
<div class="footerSelector">
<span style="margin-right: 5px; float: right;">
<input type="button"id="btnSelected" value="Selecionar Tags"/>
<input type="button" id="btnCancelar" value="Cancelar" />
</span>
<br style="clear: both;" />
</div>
</div>
</div>
</div>
Como podemos ver el código de arriba tiene dos partes esencialmente la primera es una caja de texto con dos enlaces, que es lo que se mostrará siempre al usuario, y la segunda es una div llamada panTags que es la parte que nosotros manejaremos con jquery para generar la funcionalidad del control, interiormente en esta div esta la div tagsList que es donde cargaremos las etiquetas dinámicamente. Las dos divs las ejecutamos del lado del servidor pues necesitamos modificar el marcado de las mismas.
Pero eso solo es html!
Ya se quieres código, primero definiremos algunas propiedades: para obtener el contenido del control, el número de columnas que el control muestra y el ancho de cada columna.
#region "Propiedades"
public string contentTags
{
get
{
return txtEtiquetas.Text;
}
set
{
txtEtiquetas.Text = value;
}
}
private int _columns = 3;
public int Columns {
get { return _columns; }
set { _columns = value; }
}
private int _widthColumns = 120;
public int widthClumns
{
get { return _widthColumns; }
set { _widthColumns = value; }
}
#endregion
Y ahora tenemos que mostrar las etiquetas registradas con el formato proporcionado, para lograr esto creamos un método BindTags() que enlazara las etiquetas al control. En este método generaremos las columnas del control y generaremos el formato del control según las propiedades, creando una tabla con el objeto Table y al cual le insertaremos filas con el objeto TableRow y columnas con el objeto TableCell según la cantidad de etiquetas que tengamos registradas, además generaremos el contenido de las celdas con el objeto HtmlGenericControl estos cuatro objetos nos permiten generar código html genérico, la diferencia es que los tres primeros son especialmente para tablas, filas y celdas como su nombre mismo lo dice, el ultimo nos permite crear un objeto con la etiqueta especificada como parámetro. Además si no hay etiquetas, mostraremos un link hacia una página donde puedas crear etiquetas.
private void BindTags()
{
Table tableTags = new Table();
int numRows, numCells = Columns;
List<string> lstTag = Tag.Tags.Select(t => t.Title).ToList<string>();
numRows = (lstTag.Count % numCells != 0) ? lstTag.Count / numCells + 1 : lstTag.Count / numCells;
panTags.Attributes["style"] = string.Format("width:{0}px;",numCells * widthClumns);
if (lstTag.Count != 0)
{
int k = 0;
for (int i = 0; i < numRows; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < numCells; j++)
{
TableCell cell = new TableCell();
cell.Attributes["style"] = string.Format("width:{0}px;", widthClumns);
HtmlGenericControl input = new HtmlGenericControl("input");
input.Attributes["type"] = "checkbox";
input.Attributes["class"] = "opciones";
input.Attributes["value"] = lstTag[k];
HtmlGenericControl div = new HtmlGenericControl("div");
div.Controls.Add(input);
HtmlGenericControl span = new HtmlGenericControl("span");
span.InnerHtml = lstTag[k];
div.Controls.Add(span);
cell.Controls.Add(div);
row.Cells.Add(cell);
k++;
if (k == lstTag.Count)
break;
}
tableTags.Rows.Add(row);
if (k == lstTag.Count)
break;
}
tagsList.Controls.Add(tableTags);
}
else
{
var a = new System.Web.UI.HtmlControls.HtmlAnchor();
a.HRef = "javascript:void(0)";
a.InnerHtml = "nueva etiqueta";
var lit = new Literal();
lit.Text = "No hay etiquetas registrada, porfavor cree una ";
phTags.Controls.Add(lit);
phTags.Controls.Add(a);
}
}
Ahora para cumplir con nuestro objetivo nos queda crear un método que permita registrar las etiquetas que no existen en el data store. Para lograra esto solo recogemos el contenido de la caja de texto y verificamos en el data store, si no se encuentra la registramos, para poder verificar, nuestro objeto Tag tiene una propiedad llamada Slug que es el titulo de la etiqueta libre de caracteres especiales.
public void RegisterTags()
{
string[] items = contentTags.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in items)
{
if (!string.IsNullOrEmpty(item))
{
string name = item.Trim();
Tag tag = Tag.getTag(Utils.RemoveIllegalCharacters(name));
if (tag == null)
{
//todo: codigo para registrar la nueva etiqueta
}
}
}
}
Si han leído hasta acá, se habrán dado cuenta que hay algunos métodos y clases que no están aquí, bueno en el proyecto adjunto estará el código completo al final de esta entrada.
Y donde esta eso de la selección de las etiquetas?
Continuando ahora nos toca la parte de la preselección y selección de la etiquetas, esta parte la manejaremos con jquery.
Primero creamos una función para preseleccionar las etiquetas mostradas en la caja de texto, en nuestra lista, esta función recorre el contenido del la caja de texto y comparar con la lista, si está lo selecciona, en caso contrario la deselecciona.
function PreSelectEtiquetas() {
var input = $("#<%=txtEtiquetas.ClientID%>");
var items = input.val().split(',');
$('.opciones').each(function() {
var isSelect = false;
for (var i = 0; i < items.length; i++) {
var item = $.trim(items[i]).toLowerCase();
if (typeof this.checked != "undefined") {
if (item == $.trim(this.value).toLowerCase()) {
this.checked = true;
isSelect = true;
break;
}
}
}
if (!isSelect)
this.checked = false;
});
}
Segundo creamos una función para mostrar en la caja de texto las etiquetas que nosotros selecciones en nuestra lista, esta función recorre el contenido de la caja de texto y divide el contenido con un split(‘,’) y lo almacena en un arreglo para recorrerlo y verificarlo con la lista de etiquetas; si el arreglo no tiene elementos simplemente las agrega al arreglo, en caso contrario recorre elemento por elemento verificando si el arreglo tiene un elemento que esta lista, pero no esta chekeado, quita la etiqueta del arreglo; pero si la tiene y esta checkeada, solo indica que esta seleccionada y si esta seleccionada y no esta en la lista la agregamos al arreglo. Finalmente la función muestra el contenido del arreglo en la caja de texto con un join separando cada ítem del arreglo con una coma.
function CheckEtiquetas() {
var input = $("#<%=txtEtiquetas.ClientID%>");
var items = "", isSelect, list = new Array(0);
if (input.val() != null & input.val() != "")
list = items = input.val().split(',');
$('.opciones').each(function() {
if (items.length > 0) {
isSelect = false;
for (var i = 0; i < items.length; i++) {
if (this.checked & ($.trim(items[i]).toLowerCase() == this.value.toLowerCase())) {
isSelect = true;
break;
}
if (!this.checked & ($.trim(items[i]).toLowerCase() == this.value.toLowerCase()))
list.splice(i, 1);
}
if (!isSelect & this.checked)
list.push(this.value);
}
else {
if (this.checked)
list.push(this.value);
}
});
input.val(list.join(", "));
}
Finalmente el código que interactúa con el usuario, es decir la parte que se encarga de mostrar, ocultar nuestra lista de etiquetas.
google.load("jquery", "1.3.2", { uncompressed: true });
google.setOnLoadCallback(function() {
$("body").keypress(function(e) {
if (e.which == 27)
$(".wrapper").hide();
});
$("#mostrar").click(function() {
$(".wrapper").show();
PreSelectEtiquetas();
});
$("#limpiar").click(function() {
var input = $("#<%=txtEtiquetas.ClientID%>");
input.val("");
});
$("#btnSelected").click(function() {
CheckEtiquetas();
$(".wrapper").hide();
});
$("#btnCancelar").click(function() {
$(".wrapper").hide();
});
});
Pero hasta ahora el diseño esta muy simple!
Bueno finalmente algo de css.
#wrapperShowSelector
{
border: 2px solid #c5dbec;
}
.headerSelector
{
padding: 15px;
border-bottom: #c5dbec 1px solid;
color: #2e6e9e;
background: url(images/label.png) #dfeffc repeat-x 50% 50%;
line-height:1.5em;
}
.titleSelector
{
float: left;
font-size: 16px;
font-style: italic;
font-weight: bold;
}
.contentSelector
{
padding: 12px;
background:#fff;
}
.footerSelector
{
background: #F1F1F1;
border-top: 1px solid #c5dbec;
padding: 10px 10px 15px 10px;
color: #2e6e9e;
background: url(images/label.png) #dfeffc repeat-x 50% 50%;
}
.wrapper
{
display:none;
position:absolute;
}
input , select
{
font-size:12px;
}
input[type="submit"], input[type="button"], input[type="reset"] {
height:22px;
padding:4px 12px;
border: 1px solid #B8C1CA;
font-size: 11px;
color: #666;
margin-left: 3px;
margin-top: 6px;
background-image: url(images/grid-header-bg.jpg);
}
input[type="submit"]:hover, input[type="button"]:hover, input[type="reset"]:hover {
border: 1px solid #6699cc;
background-image: url(images/a-zHover-bg.jpg);
color: #000000;
}
Y nos queda así:

Download | TagControl.rar (11.21 kb)