my select list is getting populated via a service call but I cannot select any of the values from the select list.
AJS.$("#select2-actor").auiSelect2(
{
placeholderOption: 'first',
formatResult: function(actor) {
return '<b>' + actor.text ;
},
data: function ()
{
var data = [];
AJS.$.ajax({
dataType: 'json',
type: 'GET',
url: AJS.params.baseURL+"/rest/leangearsrestresource/1.0/message/list/{actor}",
async: false
/*multiple: true*/
}).done(function(result) {
result = JSON.parse(result.value);
for (var actor in result.actors) {
data.push({
text : result.actors[actor]
});
//AJS.log(data)
}
});
return {
results: data
};
}
}
);
<div class="field-group">
<label class="label">Actor Select</label>
<input id="select2-actor" type="hidden" name="actor" style="width: 415px;" placeholder="Add an actor"/>
</div>
I am unable to figure out where I am going wrong.
Here is the JSFiddleLink
Here is the working fiddle: https://jsfiddle.net/64djszjf/14/
If you take a look at the source js file: https://aui-cdn.atlassian.com/aui-adg/5.8.13/js/aui-experimental.js, there are few lines that sets unselectable class:
populateResults: function(container, results, query) {
var populate, id=this.opts.id;
populate=function(results, container, depth) {
var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
results = opts.sortResults(results, container, query);
for (i = 0, l = results.length; i < l; i = i + 1) {
result=results[i];
disabled = (result.disabled === true);
selectable = (!disabled) && (id(result) !== undefined);
compound=result.children && result.children.length > 0;
node=$("<li></li>");
node.addClass("select2-results-dept-"+depth);
node.addClass("select2-result");
node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
which indicates that this js file requires id attribute of the object passed in.
My fix was to simply add id field to your javascript:
for (var actor in result.actors) {
data.push({
text : result.actors[actor],
id: "1"
});
AJS.log(data)
}
This also indicates that you might want to change your REST service to return ids, along with the names of Actors.
Related
I am working on a Web development project. I need to take some input like bank name in a textbox. After user starts typing 3 letters, I need to show all the matching options below (Not clear how to show). In the below options user can click any one options and the clicked text should be pasted in the same text box. All should be in html, css, js or ajax.
So far I created a text box and an ul list with no li in it and this ordered list is hidden by default. I created onkeyup event for the textbox. As the user starts typing bank names, if the text length is >=3 (Since banks keyword is minimum 3), I am filling that ul with the matching data using ajax and unhide it.
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for a Bank" title="Type in a name">
<ul id="myUL" hidden onclick="selectBank()">
And the script is:
<script>
function myFunction(){
var inp = document.getElementById('myInput');
var len = inp.value.length;
if(len>=3){
LoadBanks();
$("#myUL").show();
}else{
$('#myUL').empty();
$("#myUL").hide();
}
}
function LoadBanks(){
// for now the key is static. i will be updating it with the user input
var payload = {"key":"SBI"}
$.ajax({
url:"url",
type: "POST",
data: JSON.stringify(payload),
dataType: 'json',
success: function (data){
jsonObj = data.bankList;
var list = document.getElementById("myUL");
for (var i = 0; i < jsonObj.length; i++) {
var bank = jsonObj[i].banka;
var bankl = jsonObj[i].bankl;
var t = document.createElement('li');
t.innerHTML= bank+"-"+bankl;
list.appendChild(t);
}
},
error: function(data){
console.log(data);
}
});
}
The data is loaded sucessfully. But I don't know how to take text of which item is selected from that li's in onclick event.
You can write click event on li then inside that use $(this).text() this will give you text from li which is clicked then add that in your input-box.
Demo Code :
//just demo datas ..
var data = {
"bankList": [{
"banka": "cdc",
"bankl": "cdcde"
}, {
"banka": "cdc1",
"bankl": "cdcde1"
}, {
"banka": "cdc2",
"bankl": "cdcde2"
}]
}
function myFunction() {
var inp = document.getElementById('myInput');
var len = inp.value.length;
if (len >= 3) {
LoadBanks();
$("#myUL").show();
} else {
$('#myUL').empty();
$("#myUL").hide();
}
}
function LoadBanks() {
/*$.ajax({
url: "url",
type: "POST",
data: JSON.stringify(payload),
dataType: 'json',
success: function(data) {*/
jsonObj = data.bankList;
var list = document.getElementById("myUL");
document.getElementById("myUL").innerHTML = ""
for (var i = 0; i < jsonObj.length; i++) {
var bank = jsonObj[i].banka;
var bankl = jsonObj[i].bankl;
var t = document.createElement('li');
t.innerHTML = bank + "-" + bankl;
list.appendChild(t);
}
/*},
error: function(data) {
console.log(data);
}
});*/
}
//on click of li..
$("#myUL").on("click", "li", function() {
//get text add inside inputs
$("#selected").val($(this).text().split("-")[0])
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for a Bank" title="Type in a name">
<ul id="myUL" hidden></ul>
<input type="text" id="selected">
I have a page, where I need to filter through all kinds of data (served as JSON variable) using just pure javascript. Everything works nicely until I try to implement a datalist where the contents of that list are updated in realtime, based on user input.
var data = [{name:"Paul"},{name:"Alex"},{name:"Laura"}] // This is just example object
function updateSearch() {
let search = document.getElementById('search').value;
let options = document.getElementById('searchList');
options.innerHTML = "";
if (search.length >= 2) {
search = search.toLowerCase();
for (let d of data) {
if (d.name.toLowerCase().search(search) === 0) {
options.innerHTML += `
<option>${d.name}</option>
`;
}
}
}
}
<datalist id='searchList'></datalist>
<input type="search" id="search" list='searchList' onchange="updateSearch()">
The goal is to not show the full list of names until at least 2 characters are entered, but it just won't update until the user clicks out focuses back to search input.
One solution to achieve what you require would be to replace the event type that updateSearch() is bound to from onchange to onkeyup:
const data = [
{ name : "Foo" },
{ name : "Bar" },
{ name : "Bing" },
{ name : "Bong" },
{ name : "Boo!" }];
function updateSearch() {
let search = document.getElementById('search').value;
let options = document.getElementById('searchList');
options.innerHTML = "";
if (search.length >= 2) {
search = search.toLowerCase();
for (let d of data) {
if (d.name.toLowerCase().search(search) === 0) {
options.innerHTML += `
<option>${d.name}</option>
`;
}
}
}
}
<datalist id='searchList'></datalist>
<!-- Update to onkeyup -->
<input type="search" id="search" list='searchList' onkeyup="updateSearch()">
Doing this will cause the datalist to interactivly update as the user types. Hope that helps!
I have a Contact Form that utilizes Google Scripts. It successfully sends the email and formats it decently to my inbox, but there are 2 problems:
-I need it so that IF var key is equal to 'Action', then do not display it in the email it sends. Because right now, "Action send_message" is getting included in the email and I don't like that.
For this, I have unsuccessfully tried things like:
for (var idx in order) {
var key = order[idx];
//Skip this entry into the email output if it is the Action
if( key === 'Action') {
continue
}
It seems to not react to this code at all.
-I also need it so that if a city is selected, e.g. Alachua, that the email says 'Alachua' instead of 'Florida_Alachua'. But I can't add a NAME to an option since apparently options don't have that property. I also can't do the quick fix of changing the VALUE of the <option> to resolve this step, because of other code I have that conflicts with this route.
Google Scripts Code:
/******************************************************************************
* This tutorial is based on the work of Martin Hawksey twitter.com/mhawksey *
* But has been simplified and cleaned up to make it more beginner friendly *
* All credit still goes to Martin and any issues/complaints/questions to me. *
******************************************************************************/
// if you want to store your email server-side (hidden), uncomment the next line
var TO_ADDRESS = "myemail#email.com";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "responses";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}
Contact Form HTML
<section id="contact-form">
<form id="gform"
class="contact-form" method="post"
action="(Google Scripts URL)"
enctype="text/plain">
<p>
<label for="name">Your Name <font face="Arial" color="red">*</font></label>
<input type="text" style="height:35px;" class="heighttext required" name="name" id="name" class="required" title="* Please provide your name">
</p>
<p>
<label>Your Location <font face="Arial" color="red">*</font></label>
<select name="Location" id="column_select" style="height:35px;" class="required" title=" * Please provide your location">
<option selected value="col00">-- State --</option>
<option value="Alabama">Alabama</option>
<option value="California">California</option>
<option value="Florida">Florida</option>
</select>
<select name="City" id="layout_select" style="height:35px;">
<option disabled selected value="Florida">-- City --</option>
<option name="Alachua" value="Florida_Alachua">Alachua</option>
<option name="Alford" value="Florida_Alford">Alford</option>
</select>
</p>
<p>
<input type="submit" value="Send Message" id="submit" class="pp-btn special">
<img src="images/ajax-loader.gif" id="contact-loader" alt="Loading...">
<input type="hidden" name="action" value="send_message">
</p>
</form>
</section><!-- #contact-form -->
Form Handler Javascript
(function() {
function validEmail(email) { // see:
var re = /^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(email);
}
function validateHuman(honeypot) {
if (honeypot) { //if hidden form filled up
console.log("Robot Detected!");
return true;
} else {
console.log("Welcome Human!");
}
}
// get all data in form and return object
function getFormData() {
var form = document.getElementById("gform");
var elements = form.elements;
var fields = Object.keys(elements).filter(function(k) {
return (elements[k].name !== "honeypot");
}).map(function(k) {
if(elements[k].name !== undefined) {
return elements[k].name;
// special case for Edge's html collection
}else if(elements[k].length > 0){
return elements[k].item(0).name;
}
}).filter(function(item, pos, self) {
return self.indexOf(item) == pos && item;
});
var formData = {};
fields.forEach(function(name){
var element = elements[name];
// singular form elements just have one value
formData[name] = element.value;
// when our element has multiple items, get their values
if (element.length) {
var data = [];
for (var i = 0; i < element.length; i++) {
var item = element.item(i);
if (item.checked || item.selected) {
data.push(item.value);
}
}
formData[name] = data.join(', ');
}
});
// add form-specific values into the data
formData.formDataNameOrder = JSON.stringify(fields);
formData.formGoogleSheetName = form.dataset.sheet || "responses"; // default sheet name
formData.formGoogleSendEmail = form.dataset.email || ""; // no email by default
console.log(formData);
return formData;
}
function handleFormSubmit(event) { // handles form submit without any jquery
event.preventDefault(); // we are submitting via xhr below
var data = getFormData(); // get the values submitted in the form
/* OPTION: Remove this comment to enable SPAM prevention, see README.md
if (validateHuman(data.honeypot)) { //if form is filled, form will not be submitted
return false;
}
*/
if( data.email && !validEmail(data.email) ) { // if email is not valid show error
var invalidEmail = document.getElementById("email-invalid");
if (invalidEmail) {
invalidEmail.style.display = "block";
return false;
}
} else {
disableAllButtons(event.target);
var url = event.target.action; //
var xhr = new XMLHttpRequest();
xhr.open('POST', url);
// xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
console.log( xhr.status, xhr.statusText )
console.log(xhr.responseText);
//document.getElementById("gform").style.display = "none"; // hide form
/*
var thankYouMessage = document.getElementById("thankyou_message");
if (thankYouMessage) {
thankYouMessage.style.display = "block";
}
*/
return;
};
// url encode form data for sending as post data
var encoded = Object.keys(data).map(function(k) {
return encodeURIComponent(k) + "=" + encodeURIComponent(data[k])
}).join('&')
xhr.send(encoded);
}
}
function loaded() {
console.log("Contact form submission handler loaded successfully.");
// bind to the submit event of our form
var form = document.getElementById("gform");
form.addEventListener("submit", handleFormSubmit, false);
};
document.addEventListener("DOMContentLoaded", loaded, false);
function disableAllButtons(form) {
var buttons = form.querySelectorAll("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
}
}
})();
finally, this is the extra code that would break if I simply tried changing the value of option to, e.g., 'Alachua' instead of 'Flordia_Alachua'. https://jsfiddle.net/hmatt843/504dgmqy/19/
Thanks for any and all help.
Try console.log(key) before if( key === 'Action'). I think you'll find that key never equals 'Action', exactly. Looks like you'll need if( key === 'action'), instead.
If you wish to remove part of string value, try the replace method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
It also looks like you're trying to work with elements[k].name when you mean to be working with elements[k].value.
I believe your code should look something like...
function(k) {
if(elements[k].value !== undefined) {
return elements[k].value.replace('Florida_', '');
// special case for Edge's html collection
} else if(elements[k].length > 0){
return elements[k].item(0).value.replace('Florida_', '');
}
}
... or something to that effect.
In the future, you may want to make it easier for folks trying to help you by posting only the portions of code your having trouble with, and breaking your questions into different posts. A lot to sift through up there.
Hope this helped.
The split() method splits a String object into an array of strings by separating the string into substrings, using a specified separator string to determine where to make each split.
Var splitValue = elements[k].item(0).value.split("");
splitValue[1] will give you a string of characters after the delimeter () in this case.
So, I have two drodpowns, both dropdowns are working as expected. So, entry in second dropdowns determined by the entry selected in first drodpown. Also, I have added a script call CountrySelectionChanged on the page reload too so that second dropdown gets populated as per the intitial value of first dropdown.
<script type="text/javascript">
$(function () {
CountrySelectionChanged();
});
</script>
<div id="Admin">
Select an account:
#Html.DropDownList("countrySelection", (List<SelectListItem>)ViewBag.AvailableAccounts, new { onchange = "CountrySelectionChanged()"})
<p id="Temp">
Select a city:
<select id="City" name="City"></select>
</p>
</div>
AJAX CALL:
function CountrySelectionChanged() {
// logic taken out for brevity
$.ajax({
type: 'POST',
url: '/Settings/GetCity',
data: { accountId: accountId },
success: function (data) {
debugger;
var locationDropdown = '';
for (var x = 0; x < data.length; x++) {
locationDropdown += '<option value="' + data[x].Value + '">' + data[x].Text + '</option>';
}
$('#City').html(locationDropdown);
},
error: function () {
DisplayError('Failed to load the data.');
}
});
}
Question: Is there a way that I can use HTML Helper to display second dropdown too? Can I somehow inject the ajax return to a HTML Helper (Even if it's not strongly bound).
I'm using datatables to show some fields and two file upload button like below.
I would like to click on browse and then, after file secetion, call a web service to store file on the server and show the name beside the button, in the input field.
The problem is that the datatable is created from javascript:
function createDatatableTable(){
if ( ! $.fn.DataTable.isDataTable( '#datatableTable' ) ) {
datatableTable = $('#datatableTable').DataTable({
responsive: true,
columnDefs: [
{
targets: [3,4,5],
//set priority to column, so when resize the browser window this botton stay on the screen because have max priority
responsivePriority: 1,
orderable: false,
searchable: false,
}
],
//fix problem with responsive table
"autoWidth": false,
"ajax":{
"url": "datatable/" + $("#selectedCar").val(),
"dataSrc": function ( json ) {
if (typeof json.success == 'undefined')
window.location.href = "/DART/500";
else if (json.success){
return json.result.data;
}else{
notifyMessage(json.result, 'error');
return "";
}
},
"error": function (xhr, error, thrown) {
window.location.href = "/DART/500";
}
},
"columns": [
{ "data": "date",
"render": function (data) {
return (moment(data).format("DD/MM/YYYY"));
}
},
{ "data": "idShift" },
{ data:null, render: function ( data, type, row ) {
return data.beginKm - initialKm;
}
},
{ data:null, render: function ( data, type, row ) {
return '<div class="input-group"><span class="input-group-btn"><span class="btn btn-primary file-upload"> Browse… <input id="dat" type="file" name="file"/></span></span> <input id="datFileName" target="'+row.idAcquisition+'" type="text" class="form-control" readonly="readonly"></div>'
}
},
{ data:null, render: function ( data, type, row ) {
return '<button type="button" class="btn btn-primary" id="otherFiles">Other</button>'
}
},
{ data: "isShown", render: function ( data, type, row ) {
if (data) {
return '<input data="'+row.idAcquisition+'" type="checkbox" name="my-checkbox" checked>';
}
else {
return '<input data="'+row.idAcquisition+'" type="checkbox" name="my-checkbox">';
}
}
},
],
"fnDrawCallback": function() {
//Initialize checkbox for enable/disable user
$("[name='my-checkbox']").bootstrapSwitch({size: "small", onColor:"success", offColor:"danger"});
},
});
}
else {
datatableTable.ajax.url("datatable/" + $("#selectedCar").val()).load();
}
In this way I have given one unique id to the text area where I have to write but now how can I know the row clicked?
I have used:
//File dat upload
$('#datatableTable').on('change', 'input[name="file"]', function(event) {
var input = $(this),
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
var fieldFileName="datFileName"+ document.getElementById("datFileName").getAttribute("target");
document.getElementById(fieldFileName).value = label;
//uploadFunction('dat');
});
but it returns always the same id so use only the first file browse. I check and the id are all right.
I shouuld use an approach like var test= $(this).parent().parent().parent(); and the get the id of child?
I have used this approach for my switch button and it works:
$('#datatableTable').on('switchChange.bootstrapSwitch', 'input[name="my-checkbox"]', function(event, state) {
//CSRF attribute for spring security
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$.ajax({
type : "POST",
url : "status/" + $(this).attr('data') + "/" + state,
RESOLVED:
I fix the problem using in datatables
return '<div class="input-group"><span class="input-group-btn"><span class="btn btn-primary file-upload"> Browse… <input id="dat" type="file" name="file" target="'+row.idAcquisition+'"/></span></span> <input id="'+row.idAcquisition+'" type="text" class="form-control" readonly="readonly"></div>'
and using
$('#datatableTable').on('change', 'input[name="file"]', function(event) {
var input = $(this),
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
var test= $(this).attr('target');
document.getElementById(test).value = label;
// uploadFunction('dat');
});
Per definition an element ID must be unique throughout the whole document. Therefore
document.getElementById("datFileName")
and
$("#datFileName") // jQuery equivalent
will only return the first element with the given id. It seems though that in your table every row has the same element IDs inside.
Here's how you can make the IDs unique:
The columns.render function is given 4 arguments (although you're using only 3 of them). The fourth is metaand it has a field called row which is an index for the currently processed row. Use this to generate your ID:
...
{ data:null, render: function ( data, type, row, meta ) {
var idDat = "dat" + meta.row;
var idDatFN = "datFileName" + meta.row;
return '<div class="input-group"><span class="input-group-btn"><span class="btn btn-primary file-upload"> Browse… <input id="'+id+'" type="file" name="file"/></span></span> <input id="'+idDatFN+'" target="'+row.idAcquisition+'" type="text" class="form-control" readonly="readonly"></div>'
}
...
An alternative to this approach that is possibly cleaner is not giving the fields IDs at all but referencing them as siblings and their :nth-of-type(n) selectors. Consider reading the jQuery docs for that.
Example:
$('#datatableTable').on('change', 'input[name="file"]', function(event) {
var input = $(this),
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
// find the input's first ancestor with class input-group and inside it
// look for an input of type=text. then set its value
input.parent(".input-group").find("input[type=text]").val(label);
});
Not related the the actual problem, but you're also using the data attribute wrong. Instead of
<element data="bar" />
you should use
<element data-foo="bar" />
This way you can have multiple data attributes on each element and you can access them easily through jQuery like this:
$("element").data("foo") // getter
$("element").data("foo", "no bar") // setter