Using answers to this question, I have been able to populate a select box based on the selection of another select box. ( I posted my answer here) Pulling the data from an array structure built server-side, stored in a .js file and referenced in the html page.
Now I would like to add a third select box. If I had 3 sets of data (model, make, options) something like this (pseudo code):
cars : [Honda[Accord[Lx, Dx]], [Civic[2dr, Hatchback]],
[Toyota[Camry[Blk, Red]], [Prius[2dr,4dr]]
Ex: If Honda were selected, the next select box would have [Accord Civic] and if Accord were selected the next select box would have [Lx Dx]
How can I
1) create an array structure to hold the data? such that
2) I can use the value from one select box to reference the needed values for the next select box
Thanks
EDIT
I can create the following, but can't figure out the references in a way that would help populate a select box
var cars = [
{"makes" : "Honda",
"models" : [
{'Accord' : ["2dr","4dr"]} ,
{'CRV' : ["2dr","Hatchback"]} ,
{'Pilot': ["base","superDuper"] } ]
},
{"makes" :"Toyota",
"models" : [
{'Prius' : ["green","reallyGreen"]} ,
{'Camry' : ["sporty","square"]} ,
{'Corolla' : ["cheap","superFly"] } ]
} ] ;
alert(cars[0].models[0].Accord[0]); ---> 2dr
I prefer data structure like this:
var carMakers = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]}
];
Given the three select lists with id's: 'maker', 'model' and 'features' you can manipulate them with this (I believe this is pretty self explanatory):
// returns array of elements whose 'prop' property is 'value'
function filterByProperty(arr, prop, value) {
return $.grep(arr, function (item) { return item[prop] == value });
}
// populates select list from array of items given as objects: { name: 'text', value: 'value' }
function populateSelect(el, items) {
el.options.length = 0;
if (items.length > 0)
el.options[0] = new Option('please select', '');
$.each(items, function () {
el.options[el.options.length] = new Option(this.name, this.value);
});
}
// initialization
$(document).ready(function () {
// populating 1st select list
populateSelect($('#maker').get(0), $.map(carMakers, function(maker) { return { name: maker.name, value: maker.name} }));
// populating 2nd select list
$('#maker').bind('change', function() {
var makerName = this.value,
carMaker = filterByProperty(carMakers, 'name', makerName),
models = [];
if (carMaker.length > 0)
models = $.map(carMaker[0].models, function(model) { return { name: model.name, value: makerName + '.' + model.name} });
populateSelect($('#model').get(0), models);
$('#model').trigger('change');
});
// populating 3rd select list
$('#model').bind('change', function () {
var nameAndModel = this.value.split('.'),
features = [];
if (2 == nameAndModel.length) {
var makerName = nameAndModel[0],
carModel = nameAndModel[1],
carMaker = filterByProperty(carMakers, 'name', makerName);
if (carMaker.length > 0) {
var model = filterByProperty(carMaker[0].models, 'name', carModel)
if (model.length > 0)
features = $.map(model[0].features, function(feature) { return { name: feature, value: makerName + '.' + carModel + '.' + feature} })
}
}
populateSelect($('#feature').get(0), features);
})
// alerting value on 3rd select list change
$('#feature').bind('change', function () {
if (this.value.length > 0)
alert(this.value);
})
});
Thanks to the answer from #Marko Dunic, I was able to build an array (data) structure that can be referenced to populate 3 select boxes. I didn't use the implementation code only because I didn't completely understand it...it works as posted. I will come back to this code later as I learn jQuery.
My code is posted below (obviously, your reference to jQuery may be different)
<html><head>
<script language="Javascript" src="javascript/jquery-1.2.6.min.js"></script>
<script type="text/JavaScript">
var cars = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]
}
];
$(function() {
var options = '' ;
for (var i = 0; i < cars.length; i++) {
var opt = cars[i].name ;
if (i == 0){ options += '<option selected value="' + opt + '">' + opt + '</option>'; }
else {options += '<option value="' + opt + '">' + opt + '</option>'; }
}
$("#maker").html(options); // populate select box with array
var options = '' ;
for (var i=0; i < cars[0].models.length; i++) {
var opt = cars[0].models[0].name ;
if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
$("#model").html(options); // populate select box with array
var options = '' ;
for (var i=0; i < cars[0].models[0].features.length; i++) {
var opt = cars[0].models[0].features[i] ;
if (i==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
$("#feature").html(options); // populate select box with array
$("#maker").bind("click",
function() {
$("#model").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
if (cars[i].name == this.value) {
var options = '' ;
for (var j=0; j < cars[i].models.length; j++) {
var opt= cars[i].models[j].name ;
if (j==0) {options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break;
}
}
$("#model").html(options); // populate select box with array
$("#feature").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
for(var j=0; j<cars[i].models.length; j++) {
if(cars[i].models[j].name == $("#model").val()) {
var options = '' ;
for (var k=0; k < cars[i].models[j].features.length; k++) {
var opt = cars[i].models[j].features[k] ;
if (k==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break;
}
}
}
$("#feature").html(options); // populate select box with array
});
$("#model").bind("click",
function() {
$("#feature").children().remove() ; // clear select box
for(var i=0; i<cars.length; i++) {
for(var j=0; j<cars[i].models.length; j++) {
if(cars[i].models[j].name == this.value) {
var options = '' ;
for (var k=0; k < cars[i].models[j].features.length; k++) {
var opt = cars[i].models[j].features[k] ;
if (k==0){options += '<option selected value="' + opt + '">' + opt + '</option>';}
else {options += '<option value="' + opt + '">' + opt + '</option>';}
}
break ;
}
}
}
$("#feature").html(options); // populate select box with array
});
});
</script>
</head> <body>
<div id="selection">
<select id="maker"size="10" style="{width=75px}"></select>
<select id="model" size="10" style="{width=75px}"></select>
<select id="feature" size="10"style="{width=75px}"></select>
</div></body></html>
I really liked the solution by #Marko Dunic, but it didn't meet my needs for attaching IDs to the options. Once I attached the IDs, I realized that I could make the JS code even smaller and simpler. My solution is designed for when the data comes from a relational database, and the JSON input data retains the relational structure with Primary/Foreign Keys. Here is the JSON data:
<html lang="en">
<head>
<title>Populate a select dropdown list with jQuery - WebDev Ingredients</title>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
var types = [
{ typeID: 1, name: 'Domestic'},
{ typeID: 2, name: 'Import'},
{ typeID: 3, name: 'Boat'}
]
var makes = [
{ typeID: 1, makeID: 1, name: 'Chevy'},
{ typeID: 1, makeID: 2, name: 'Ford'},
{ typeID: 1, makeID: 3, name: 'Delorean'},
{ typeID: 2, makeID: 4, name: 'Honda'},
{ typeID: 2, makeID: 5, name: 'Toyota'},
{ typeID: 2, makeID: 6, name: 'Saab'}
]
var model = [
{ makeID: 1, modelID: 1, name: 'Camaro'},
{ makeID: 1, modelID: 2, name: 'Chevelle'},
{ makeID: 1, modelID: 3, name: 'Nova'},
{ makeID: 2, modelID: 4, name: 'Focus'},
{ makeID: 2, modelID: 5, name: 'Galaxie'},
{ makeID: 2, modelID: 6, name: 'Mustang'},
{ makeID: 4, modelID: 7, name: 'Accord'},
{ makeID: 4, modelID: 8, name: 'Civic'},
{ makeID: 4, modelID: 9, name: 'Odyssey'},
{ makeID: 5, modelID: 10, name: 'Camry'},
{ makeID: 5, modelID: 11, name: 'Corolla'}
]
//
// Put this in a stand alone .js file
//
// returns array of elements whose 'prop' property is 'value'
function filterByProperty(arr, prop, value) {
return $.grep(arr, function (item) { return item[prop] == value });
}
// populates select list from array of items given as objects: { name: 'text', value: 'value' }
function populateSelect(el, items) {
el.options.length = 0;
if (items.length > 0)
el.options[0] = new Option('please select', '');
$.each(items, function () {
el.options[el.options.length] = new Option(this.name, this.value);
});
}
// initialization
$(document).ready(function () {
// populating 1st select list
populateSelect($('#sType').get(0), $.map(types, function(type) { return { name: type.name, value: type.typeID} }));
// populating 2nd select list
$('#sType').bind('change', function() {
var theModels = filterByProperty(makes, 'typeID', this.value);
populateSelect($('#sMake').get(0), $.map(theModels, function(make) { return { name: make.name, value: make.makeID} }));
$('#sMake').trigger('change');
});
// populating 3nd select list
$('#sMake').bind('change', function() {
var theSeries = filterByProperty(model, 'makeID', this.value);
populateSelect($('#sModel').get(0), $.map(theSeries, function(model) { return { name: model.name, value: model.modelID} }));
});
});
</script>
</head>
<body>
Enter values, click submit, and look at the post parameters
<form method="get" action="index.php">
<div id="selection">
<select id="sType" name="type_id" style="{width=75px}"></select>
<select id="sMake" name="make_id" style="{width=75px}"></select>
<select id="sModel" name="model_id" style="{width=75px}"></select>
</div>
<input type="submit">
</form>
</body>
</html>
Notice that my solution shifts the functionality so that Make-Model are the 2nd and 3rd text boxes, and Type ( domestic, import, boat, etc. ) are the 1st level. I got the boilerplate JS down to 23 lines (less comments) while retaining good formatting.
The JSON data is very easy to render from SQL queries, which are cached in java Lists on init because the Type-Make-Model rarely change. I don't use any dynamic AJAX because that complicates the architecture, and I have a relatively small list of available values, so I just send it at the page request.
"Solutions should be a simple as possible, but no simpler" - A. Einstein
You should take a look here for select box manipulation.
For what you want, i think JSON will do the right job for you.
Anyhow, if i were you, i will do this way:
When I change first select, i do an ajax request. With ajax response, i will populate the second box. Same for second box and there you have the third box populated with right data.
Related
this is my first post, i am a javascript newbie, and english is not my native language, so sorry if i my explanations are not as you expect.
So, i am trying to populate a select list with the result of an ajax database query.
the query returns a string:
'[["Saphir","1","10"],["Serval","2","10"],["Sygma","3","10"],["Swan","4","10"]]'
My purpose is to use this result to populate a select list with e.g. for the first option:
Saphir as the text, and "1" for the value.
Here is my last code, no error returned by the Chrome console.
I have tried to adapt so many others found here and there, but i still didn't succeed yet.
this code fills a list, but doesn't allow any selection.
#bfLabel410is the select list ID
function ff_sidefab_action(element, action) {
switch (action) {
case 'change':
jQuery.ajax(
{
type: "POST",
url: "/BMWK1census/ajaxsidemodelist.php",
data: { code: ff_getElementByName('sidefab').value },
success: function (data) {
var obj = JSON.parse(data);
console.log(obj);
var result = [];
var keys = Object.keys(obj);
console.log(typeof keys)
keys.forEach(function (key) { result.push(obj[key]); });
jQuery('#bfLabel410').empty();
jQuery('#bfLabel410').append(jQuery('<option>', { value: '', text: 'Choisir une option' }));
for (var i = 0; i < result.length; i++) {
console.log(result[i]);
alert(result[i][0]);
jQuery('#bfLabel410').append(jQuery('<option>', { value: result[i][1], text: result[i][0] }));
} // fin boucle for
} // fin success
} // fin params ajax
); // fin jQuery.ajax()
break;
default: ;
} // fin switch
}
jQuery('#bfLabel410').append(jQuery('<option value="">' + 'Choisir une option' + '</option>' ));
for (var i = 0; i < result.length; i++) {
console.log(result[i]);
alert(result[i][0]);
jQuery('#bfLabel410').append(jQuery('<option value="' + result[i][1] + '">' + result[i][0] + '</option>'));
}
I'm trying to dynamically render values I am pulling from SQL that looks like this:
into something that looks like this:
I already have HTML and CSS placed and I am approaching this using $.each but I cant seem to populate the inside of the view tree:
EDIT:
here is my script:
AjaxGet('GetUserAppFeatures', { "uid": userid }, false, true)
.success(function (result) {
$.each(result.model, function (val) {
var li = $('<li></li>');
li.append('<span class="caret">' + result.model[val].AppName + '</span> <input type="checkbox" id="chkApp' + result.model[val].AppId + '">');
var ul = $('<ul class="nested"></ul>');
$.each(result.model[val], function (index) {
ul.append('<li>' + result.model[val].FeatureName[index] + '</li> <input type="checkbox" id="chkApp' + result.model[val].FeatureId[index] + '">');
li.append(ul);
});
treeview.append(li);
});
});
For this type of data you need to group by.
var yourData = [
{Name : "Forms", value : "Request"},
{Name : "Forms", value : "Report"},
{Name : "Forms", value : "Password"},
{Name : "Energy", value : "Report"},
{Name : "Energy", value : "CUstomer Multiplier"},
{Name : "Energy", value : "Product Feedback"},
];
Renderdata();
function Renderdata(){
var data = groupBy(yourData,"Name");
var html = '';
for(var i= 0 ; i < data.length; i++){
html += "<div>"+data[i][0].Name+" </div>"+"<ul>";
for(var j= 0 ; j < data[i].length; j++){
html += "<li>"+data[i][j].value+"</li>";
}
html += "</ul>";
}
$('#div').html(html);
}
function groupBy(collection, property) {
var i = 0, val, index,
values = [], result = [];
for (; i < collection.length; i++) {
val = collection[i][property];
index = values.indexOf(val);
if (index > -1)
result[index].push(collection[i]);
else {
values.push(val);
result.push([collection[i]]);
}
}
return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div"></div>
Perhaps you need an intermediate step where you construct an array modelling the second image you have there. Something like:
// Do this before $.each()
var sql_data = {
Forms: [],
Energy: []
};
// Inside of $.each() do something like this:
sql_data[col_1].push(col_2);
Where "col_1" and "col_2" are respectively the first and second columns in your data. Then you can use that "sql_data" object to create the HTML that you need.
I have simple code which allows me display related product based on tags, but I would like expand that code, that can I type more than one tag. At this moment I can run only:
<script type="text/javascript">category('tag1');</script>
And I got every product with 'tag1' in their tags. In this case name1 and name2.
var products = [
{
name: 'name1',
tags: ['tag1', 'tag2', 'tag3'],
},
{
name: 'name2',
tags: ['tag1', 'tag3', 'tag4', 'tag5'],
},
{
name: 'name3',
tags: ['tag2', 'tag5', 'tag6'],
}
];
var finalHtml = "";
function category(tag) {
return products.filter(function(product){
if (~product.tags.indexOf(tag)) {
finalHtml += '<li>' + product.name + '</li>';
document.getElementById("related_prod").innerHTML = finalHtml;
}
});
}
What I expect?
When I will run that code:
<script type="text/javascript">category('tag1, tag6');</script>
I would like see every product which has tag1 OR tag2 in their tags. In this case it should be name1 and name3.
Here is a solution using ECMAScript2015:
var products = [
{
name: 'name1',
tags: ['tag1', 'tag2', 'tag3'],
},
{
name: 'name2',
tags: ['tag1', 'tag3', 'tag4', 'tag5'],
},
{
name: 'name3',
tags: ['tag2', 'tag5', 'tag6'],
}
];
function category(...tags) {
let related = document.getElementById("related_prod");
// clear output
related.innerHTML = '';
// turn array values into object properties for faster lookup
tags = tags.reduce((tags, tag) => (tags[tag] = 1, tags), {});
// find products that have at least one of the tags
products.filter(product => product.tags.some(tag => tags[tag]))
// display the names of the found products
.forEach(product => {
let li = document.createElement('li');
li.textContent = product.name;
related.appendChild(li);
});
}
category('tag4','tag5');
<ul id="related_prod"></ul>
This can be mor generic as i understand from your requirement you wanted "OR" not "AND" so the answer can be :
function category() {
var args = Array.prototype.slice.call(arguments);
return products.filter(function(product){
args.forEach(function(arg){
if (product.tags.indexOf(arg)> -1) {// readability
finalHtml += '<li>' + product.name + '</li>';
document.getElementById("related_prod").innerHTML = finalHtml;
}
})
});
}
Edit: For a better solution that have good seperation and readable one (assuming you are using ecmascript5 shim)
function findProducts(){
var args = Array.prototype.slice.call(arguments);
var foundProducts = [];
products.forEach(function(product) {
args.forEach(function(arg){
if(product.tags.indexOf(arg) > -1 && foundProdutcs.indexOf(product) == -1)
foundProducts.push(product);
}
});
return foundProducts;
}
function doSomethingWithTheProducts() {
var products = findProducts.apply(this,arguments);
var finalHtml = "";
products.forEach(function(product){
finalHtml += "<li>" + product.name + "</li">;
});
document.getElementById("related_prod").innerHTML = finalHtml;
}
doSomethingWithTheProducts('tag1','tag2');
I have a jquery autocomplete which is not doing anything. I have used the code from here. It works in their example.
There are some changes... First, array is created from a viewModelList and it works. here is a small part of it:
var suburbs = [
{
id: "17023",
suburb: "Epsom",
postCode: "3551",
state: "VIC"
},
{
id: "17024",
suburb: "Muskerry",
postCode: "3557",
state: "VIC"
}
I have endeavoured to use messages to indicate the respose - what it is but even the messages dont work... I cannot even get the response value..
I created a div below the form for the messages and they work having been tested using a click function.. I did try a ".change" function on the "#Suburbs" id and also got nothing..
Here is the code:
<script>
(function ($) {
$(function () {
var suburbs = [
#for (var i = 0; i < Model.SuburbAndPostcodesList.Count; i++) {
<text>{
id: "#Model.SuburbAndPostcodesList[i].SuburbsAndPostcodesId",
suburb: "#Model.SuburbAndPostcodesList[i].Suburb",
postCode: "#Model.SuburbAndPostcodesList[i].PostCode",
state: "#Model.SuburbAndPostcodesList[i].State.ShortName"
}#(i == Model.SuburbAndPostcodesList.Count - 1 ? "" : ",")</text>
}
];
$("#Suburb").autocomplete({
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
//addMessage(" sniffing: '" + item + "'<br/>");
return matcher.test(item.suburb);
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
select: function (value, data) {
if (typeof data == "undefined") {
addMessage('You selected: ' + value + "<br/>");
} else {
addMessage('You selected: ' + data.item.value + "<br/>");
}
}
});
function addMessage(msg) {
$('#msgs').append(msg);
}
});
});
</script>
The id "#Suburb" is correct and worked for a simple version of .autocomplete.
EDIT: here is page code for the javascript.. Hope this is what you were after..
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe-a3Ichp0LEgzXczKo"></script>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="/lib/jquery-ui/jquery-ui.js"></script>
<script>
(function ($) {
$(function () {
var suburbs = [
{
id: "17023",
suburb: "Epsom",
postCode: "3551",
state: "VIC"
},
{
id: "17024",
suburb: "Muskerry",
postCode: "3557",
state: "VIC"
},
...
{
id: "17055",
suburb: "Bonnet Hill",
postCode: "7053",
state: "TAS"
},
{
id: "17056",
suburb: "Wellington Park",
postCode: "7054",
state: "TAS"
}
];
$("#Suburb").autocomplete({
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
//addMessage(" sniffing: '" + item + "'<br/>");
return matcher.test(item.suburb);
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
select: function (value, data) {
if (typeof data == "undefined") {
addMessage('You selected: ' + value + "<br/>");
} else {
addMessage('You selected: ' + data.item.value + "<br/>");
}
}
});
function addMessage(msg) {
$('#msgs').append(msg);
}
});
});
</script>
EDIT2: Here is the div element "suburb" as I think its probably a good idea to see what the autocomplete is working on.
<div class="form-group">
<label class="col-md-2 control-label" for="Suburb">Suburb:</label>
<div class="col-md-10">
<input class="form-control" type="text" data-val="true" data-val-required="A suburb name is required" id="Suburb" name="Suburb" value="Eaglehawk" />
<span class="text-danger field-validation-valid" data-valmsg-for="Suburb" data-valmsg-replace="true" />
</div>
</div>
Okay, a few things:
first: your jQuery .ready() function isn't running at all. You are combining several shorthand and advanced techniques, and they are not working. (More details on this in the comments below) Until you can do some research and get the concepts down, probably better to use the long-hand method, and just do
$(document).ready(function() {
});
Second: when you do $('#Suburb'), that means you have to have an element with id="Suburb" someplace in your document. Your input didn't have that.
Third: your a array that you are returning is an array of objects which your autocomplete won't recognize. You either need to return an array of strings, or an array of objects in this format: { label: "Choice1", value: "value1" }. The easiest way to accomplish this was just to add .map into your existing code, right after the .grep:
source: function (req, responseFn) {
addMessage("search on: '" + req.term + "'<br/>");
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp("^" + re, "i");
var a = $.grep(suburbs, function (item , index) {
return matcher.test(item.suburb);
});
a = $.map(a, function(x){
return x.suburb;
});
addMessage("Result: " + a.length + " items<br/>");
responseFn(a);
},
That being said, I have made some mods to your code (making some assumptions) and here is a working fiddle. Sorry, I had already started working on my own fiddle by the time you added yours. It was easier to just continue with the fiddle that I created than it was to modify yours.
Im using Jquery datatables to construct a table.
My requirement is like below
This is not a static table, and we are rendering it using json data. Here I'm, rendering the rows dynamically using "aoColumns".
Is there any way to use rowspan so that the cells (1,2,David,Alex) can be spanned.
Does datatables support this kind of table ?
Datatables does not support this kind of grouping out of the box.
But, as in many cases, there is a plugin available.
It is called RowsGroup and is located here: Datatables Forums. A live example is also included.
If you change the JS part in this example to the below you will have your desired output presented to you in the output window.
$(document).ready( function () {
var data = [
['1', 'David', 'Maths', '80'],
['1', 'David', 'Physics', '90'],
['1', 'David', 'Computers', '70'],
['2', 'Alex', 'Maths', '80'],
['2', 'Alex', 'Physics', '70'],
['2', 'Alex', 'Computers', '90'],
];
var table = $('#example').DataTable({
columns: [
{
name: 'first',
title: 'ID',
},
{
name: 'second',
title: 'Name',
},
{
title: 'Subject',
},
{
title: 'Marks',
},
],
data: data,
rowsGroup: [
'first:name',
'second:name'
],
pageLength: '20',
});
} );
Here is a screenshot of the result:
I tried the RowsGroup plugin, but it achieves this just by hijacking the DataTables sort mechanism. If you tell it to group a given column, what it does for you is basically to apply a sort to that column that you can't turn off. So, if you want to sort by another column, you can't. That didn't work in my application.
Instead, here's a working fiddle for a recipe that allows you to achieve this result:
https://jsfiddle.net/bwDialogs/fscaos2n
The basic idea is to flatten all of your multi-row data into a single row. Content in your 2nd, 3rd, etc. rows are stored as a hidden <script> template tag within your first row.
It works by using DataTables' drawCallback function to manipulate the DOM once DataTables has rendered it, without confusing DataTables by having to try parsing rowspan cell content.
Since this modifies the DOM after DataTables has done its magic, your multi-row sections will stick together even with pagination, searching, and sorting.
Cheers.
add a below code and modify according to your requirement
$(window).on("load",function() {
MakeRows();
addRowspan();
$(".paginate_button").on("click", function() {
MakeRows();
addRowspan();
});
});
function MakeRows() {
var tmp_tbl = $("#dashboardDetails");
var _l = tmp_tbl.find("tr");
var _td = "",_t_td = "", old_txt = "",_t_txt = ""; _tr_count = 1;_tr_countadd = 1;
for(i = 0;i< _l.length; i ++) {
_t_td = tmp_tbl.find("tr").eq(i).find("td").eq(0).find("span");
_t_txt = $(_t_td).text();
_t_txt = _t_txt.replace(/\//,"_");_t_txt = _t_txt.replace(/\//,"_");
if (_t_txt.length > 0) {
if(_t_txt != old_txt) {
if($(_l).eq(i).hasClass(_t_txt) == false) {
_tr_count = 1;_tr_countadd = 1;
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i);
}
old_txt = _t_txt;
} else {
_tr_count = _tr_count + 1;
if (_tr_countadd == 1) {
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i)
.addClass("hiddenClass").addClass("maintr").attr("trcount", _tr_count).attr("addedtrcount", "maintr");
_tr_countadd = _tr_countadd + 1;
} else {
$(_l).eq(i).addClass("" + _t_txt + "").addClass(_t_txt + "_" + i)
.addClass("hiddenClass").attr("trcount", _tr_count)
}
}
}
_t_td = "";
}
}
function addRowspan() {
var t_txt = "";
var _alltrmain = $(".maintr");
var _h_td = ["0","10","11","12","13"];
for (i = 0; i <= _alltrmain.length; i ++) {
for (j = 0; j <= _h_td.length; j ++) {
t_txt = $(_alltrmain).eq(i).attr("trcount");
$(_alltrmain).eq(i).prev().find("td").eq(_h_td[j]).attr("rowspan", t_txt);
}
}
}