How to recreate a table with jQuery DataTables - javascript

I'm essentially using the top answer here ( from sdespont) to try to destroy some tables.
I have one table that shows me the status of a .csv file being uploaded.
FileuploadTable:
FileName FileType FileSize AvailableActions
I have a second table that is the table displaying data from the .csv file.
I need provide the user the ability to reset the form, i.e. get rid of the .csv, and get rid of all of the data, destroy() the two tables separately, and empty() them of all the data that was there initially.
Here is the issue I'm running into.
I can't seem to set the column titles of FileUploadTable after destroy() and empty(). When I attempt to upload a new file, the elements are still on the page, just empty, though the same initialization is being called
I can't seem to get rid of the column titles in CSVTable after destroy() and empty(). When I attempt to upload a different csv, it tries to match column headers to the ones that should have been destroyed, but they don't match because, though CSVTable was destroyed and emptied, the column titles are still there...?
Not sure what I'm missing. They're being set properly on initial create.
$(elem).DataTable()
Can anyone show me a basic working implementation of destroying/emptying datatables, then re initializing with different data, so I can try to mimic it. My brain is mush from looking at their docs for the last 3 days, making no progress.
Example of my data object
[
{
//key = column title
//"val" = data in row
//object = row
key: "val",
//i.e.
FirstName: "Bob",
LastName: "Barker",
Age: 800,
//etc
},
//etc
]

OK. You can make a simple iteration over your data using Object.keys() that produces a column object on the fly holding corresponding data and title values :
var columns = [], keys = Object.keys(data[0]);
for (var i=0;i<keys.length;i++) {
columns.push({ data: keys[i], title: keys[i] });
}
Use that inside a general function that initialises the table and take care of destroying and emptying if already initialized :
var table = null;
function initTable(data) {
var columns = [], keys = Object.keys(data[0]);
for (var i=0;i<keys.length;i++) {
columns.push({ data: keys[i], title: keys[i] });
}
if (table) {
table.destroy();
$('#example').empty();
}
table = $('#example').DataTable({
data: data,
columns : columns
})
}
Now imagine the following is the success handlers of your AJAX calls, or however you get the new data that should be populated to the table :
$('#insert1').on('click', function() {
var data = [
{ FirstName: "Bob", LastName: "Barker", Age: 800 },
{ FirstName: "John", LastName: "Doe", Age: 'N/A' }
]
initTable(data);
})
$('#insert2').on('click', function() {
var data = [
{ Animal : "Lion", Taxon : 'Panthera leo' },
{ Animal : "Cheetah", Taxon : 'Acinonyx jubatus' }
]
initTable(data);
})
demo -> http://jsfiddle.net/d5pb3kto/

Related

how can i replace one value from list object and same new value assign to same object list using angularjs?

var test = list contains 10 rows with 4 columns;
test.then(function(d)){
$scope.mylist = d.data;
}
example:my list contains one row like
name:"rajesh";
id:10009;
branch:"dotnet";etc...
here i want to replace branch dotnet to angular for all rows and again that value assign same to same object.
means i need output like this?
name:"rajesh";//1st row
id:100009;
branch:"angular";
name:"sai";//2nd row
id:1004;
branch:"angular"; like this
please suggest i am new to angularjs
FYI, You are using very old JavaScript syntax. (Recommended to upgrade)
Anyways, extending the code snippet in your question.
Update
question is different from what you are asking in comments. if you are looking for code to get it done. Here it is...
const results = [
{ Name: 'raju', Id: 1009, Branch: 'cse' },
{ Name: 'sai', Id: 1019, Branch: 'ece' },
{ Name: 'nandu', Id: 1089, Branch: 'civil' }
];
const output = results.map(user => {
user.Name = '****';
return user;
});
Just use map to transform your data.
var test = list contains 10 rows with 4 columns;
test.then(function(d)){
$scope.mylist = d.data.map(function(user) {
if (user.branch === 'dotnet') {
user.branch = 'angular';
}
return user;
});
}

mongoose find() sorting and organizing returned results from a product database in js

I have a problem with organizing my mongoDB data to send to my page in my res and cant figure out how to do the correct js. Here is a simplified version of my schema
var productSchema = new mongoose.Schema({
medium: String,
brand: String,
group: String
});
Here is what a typical entry looks like
medium :"Acrylic",
brand :"liquitex",
group :"heavy body"
there are many more entries in the schema, but these are the only ones I need to be able to sort and organize the returned results with. The problem is I have a route that returns all colors in my database and I want to be able to display them in sections on my page that are grouped under Brand, and then has the individual colors listed under the correct group.
The problem is there are paints from other brands that fall into the heavy body group and so when I use a filter function to sort my data by group, some brands get mixed together. I cant filter by brand, because some brands have acrylic and watercolor so then those get lumped together.
I need some way to filter the returned results of a
mongoose.find({})
that can use the group data as a filter, but then filter those results by the brands so they get separated into the correct brand categories.
I have this so far:
this is all a stripped down version of my app.js file:
//finds all colors in the DB
Color.find({}).lean().exec(function( err, colors)
var groups = [];
// find all groups in the databse
colors.forEach( function(color){
groups.push(color["group"]);
});
//returns only unique names to filter out duplicates
var groupTypes = Array.from(new Set(groups));
var tempVariableBrands = [];
// this sorts all returned paints into their respective group, but we get paints from multiple brands under the same group and that is not good
groupTypes.forEach( function(group){
var name = group;
var result = colors.filter(obj => { return obj.group === group });
tempVariable.push( {group : name, result } );
});
// the tempVariable gets sent to my page like so
res.render("landing", {colorEntry:tempVariable} );
and this works fine to allow me to display each paint by its grouping, but that fails when there is more than one paint from a different manufacturer that is considered the same group like a "heavy body". This is my ejs on my page that works fine:
<% colorEntry.forEach( function(entry){ %>
<div class="brandBlock">
<div class="brandTitle">
<span><%=entry.result[0].brand%> - <%=entry.result[0].group%></span>
I for the life of me cant seem to figure out the combination of filter() and maybe map() that would allow this kind of processing to be done.
My database has like 600 documents, colors from a number of different manufacturers and I don't know how to get this as a returned structure: lets say this is a few colors in the DB that get returned from a mongoose find:
[{ medium: "Oil",
brand: "Gamblin",
group: "Artists oil colors"},
{ medium: "Acrylic",
brand: "Liquitex",
group: "Heavy Body"},
{ medium: "Acrylic",
brand: "Golden",
group: "Heavy Body"}
]
i need to organize it like this or something similar. It can be anything that just sorts this data into a basic structure like this, I am not confined to any set standard or anything, this is just for personal use and a site I am trying to build to learn more.
returnedColors = [ { brand: "Gamblin", group: "Artists oil colors", { 50 paints colors returned} },
{ brand: "liquitex" , group: "heavy body", { 20 paint colors returned } },
{ brand: "golden" , group: "heavy body",{ 60 paint colors returned} }
];
I am not a web developer and only write some web code every 6 months or so and have been trying how to figure this out for the last 2 days. I can't wrap my head around some of the awesome filter and map combo's i have seen and cant get this to work.
Any help or advice would be great. I am sure there are many areas for improvement in this code, but everything was working up until I entered paints that were from different brands that had the same group type and i had to try to rewrite this sorting code to deal with it.
It boils down to needing to be able to iterate over the entire set of returned documents from the DB and then sort them based off 2 values.
UPDATE:
I was able to get something that works and returns the data in the format that I need to be able to send it to my ejs file and display it properly. The code is rather ugly and probably very redundant, but it technically works. It starts off by using the group value to run over paints since each set of paints will have a group name, but can sometimes share a group name with a paint from another brand like "heavy body".
groupTypes.forEach( function(group){
var name = group;
var result = colors.filter(obj => { return obj.group === group });
// this gets brand names per iteration of this loop so that we will know if more than one brand of paint
// has the same group identity.
var brands = [];
result.forEach( function(color){
brands.push(color["brand"]);
});
// This filters the brand names down to a unique list of brands
var brandNames = Array.from(new Set(brands));
// if there is more than one brand, we need to filter this into two separate groups
if( brandNames.length > 1){
//console.log("You have duplicates");
brandNames.forEach( x => {
var tmpResult = [...result];
var resultTmp = result.filter(obj => { return obj.brand === x });
result = resultTmp;
//console.log("FILTERED RESULT IS: ", result);
tempVariable.push( {brand: x ,group : name, result } );
result = [...tmpResult];
});
}else{
tempVariable.push( {brand: result[0].brand ,group : name, result } );
}
});
if anyone can reduce this to something more efficient, I would love to see the "better" way or "right" way of doing something like this.
UPDATE2
Thanks to the answer below, I was put on the right track and was able to rewrite a bunch of that long code with this:
Color.aggregate([
{
$sort: { name: 1}
},
{
$group: {
_id: { brand: '$brand', group: '$group' },
result: { $push: '$$ROOT' }
}
},
{ $sort: { '_id.brand': 1 } }
], function( err, colors){
if(err){
console.log(err);
}else{
res.render("landing", {colorEntry:colors, isSearch:1, codes: userCodes, currentUser: req.user, ads: vs.randomAds()} );
}
});
Much cleaner and appears to achieve the same result.
Since you're using MongoDB, "right" way is to utilize an Aggregation framework, precisely, $group stage.
Product.aggregate([{
$group: {
_id: { group: '$group', brand: '$brand' },
products: { $push: '$$ROOT' }
}
}])
This will output array of objects containing every combination of brand and group, and push all relevant products to corresponding subarray.
Combine it with $project and $sort stages to shape your data further.

Axios response/return is getting data but need indexing

I currently have a working axios return, showing that my objects are holding the correct returned data. But my issue is this: The data that is coming to the return, while correct, is not grouped by ID, so even though I only have 4 unique items I get 8 rows in my return because each item has a name and a comment which are returned separately. The issue here is that for each ID/Item, I want to show the Name and other top level data in an HTML table but if you click on it then the modal would show more sub level data, like the comment.
For example, I'm getting this in the return:
0:{
item_id: "123",
item_comment_type: "Title",
item_type: "2",
item_comment:"This is an Item"
}
1:{
item_id: "123",
item_comment_type: "Comment",
item_type: "2",
item_comment:"This is a comment"
}
2:{
item_id: "1245",
item_comment_type: "Title",
item_type: "3",
item_comment:"This is a new Item"
}
3:{
item_id: "1245",
item_comment_type: "Comment",
item_type: "3",
item_comment:"This is a new Comment"
}
So I want one section to only show 2 rows since I only have 2 items, and it should show the item ID and item Title, but then if it is clicked and the modal pops up I still want all data associated with it to show there. I really just want to group these things by ID so that at the top level I have the ID and the comment if the comment type is title, and everything else in a level below it.
Here's the axios call:
axios.get('/home/items' )
.then((response) => {
const events = response.data.map(item => {
return {
id: item.item_id,
title: item.item_comment, // if item_comment_type is Title
comment: item.item_comment, // if item_comment_type is Comment
type: item.item_type
};
});
this.dateEvents = events;
this.events = events;
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
});
You can use an object to map the items based on item_id.
let events = {};
response.data.forEach(item => {
if (typeof events[item.item_id] === 'undefined') {
events[item.item_id] = {
id: item.item_id,
comments: [],
title: '',
};
}
if (item.item_comment_type === 'Title') {
events[item.item_id].title = item.item_comment;
} else {
events[item.item_id].comments.push(item.item_comment);
}
});
This will give you an object, indexed by item_id, having title and a comments array which you can then loop using v-for (assuming you're using Vue.JS since this question is tagged that way).
Your problem's solution can be obtained my storing mapping of item_id to respective data.
Suppose after your events array is being structured, loop accordingly to store item_id as key and array of respective grouping for that ID. Also update array for respective accordingly.
let newObj = {};
events.forEach((item,index) => {
console.log('item',item)
newObj[item.item_id] = newObj[item.item_id] ? [...newObj[item.item_id],item]:[item]
});

How to control array sorting in knockout.mapping?

Please find the jsfiddle example. I have an observable array of persons, each person has id, firstName and lastName. User sorts this array by any property, in both directions.
Then, at some point, I need to update my array, which I do using knockout.mapping.fromJS function:
this.rockStarsMapping = {
create: function (options) {
// just to make sure that key works
console.log('created');
return options.data;
},
key: function(data) {
return data.id;
}
};
this.rockStars = ko.observableArray([]);
this.getRockStars = function() {
// here should be some ajax call instead of a stub
var newRockStars = [
{ id: 1, firstName: "John", lastName: "Lehnon" },
{ id: 2, firstName: "Paul", lastName: "McCartney" },
...
];
ko.mapping.fromJS(newRockStars, self.rockStarsMapping, self.rockStars);
};
The problem is, that new array is sorted by id (for example), and this sorting prevails over sorting in existing array.
My current solution is to remember current sort column name and sort direction, but it doesn't work right, because other columns may have other sort directions. For example, in my jsfiddle code, try to sort by Id descending first (6, 5, 4, ...), then sort by First name. Now if you click "Get rock stars", the sorting order in Id column changes, which is not a desired behavior.
How to keep sorting order as is? And what more important - how to make sure new items would be in the right place of an array?

knockout: extending mapping to complex JSON

I receive a complex JSON from the server. Let it be next:
var data = [{
name: "name1",
items:[
{
name:"name11",
subItems:[{
name:"name111",
children[
{id:1,name:"child1111",status:"good"},
{id:2,name:"child1112",status:"bad"},
{id:3,name:"child1113",status:"good"}
]},
{
name:"name112",
children[
{id:4,name:"child1121",status:"good"}]
}]
},
{
name:"name12",
subItems:[{
name:"name121",
children[
{id:5,name:"child1211",status:"bad"}]
}]
}]
},
{
name: "name2",
items:[
{
name:"name21",
subItems:[{
name:"name111",
children[
{id:7,name:"child2111",status:"good"}
]}]
}]
}];
So I have the list of objects each one contains name and items properties. Items is property of the similar list of objects each one contains name and subItems properties. subItems property same to previous and has name and children properties. children is list of my entities. I use mapping for filling my ViewModel.
First of all I can't image how to set as key id in my entity. I am wondering how to "dive" to it. Moreover, I need to extend my entity. Add the compute property like next example:
computProp: ko.computed(function() {return name+status;})
I don't want to create js classes, because I don't see benefits of mapping on this case. I can implement manual mapping in this case. It would be more clear for me.
So any idea, suggesting or critics are welcome.
PS: I have searched/read similar topics
You must explicit declare the children viewmodel to get this behaviour, but you still benefit from getting all the mapping done
http://jsfiddle.net/uXMhA/
ChildViewModel = function(data) {
ko.mapping.fromJS(data, {}, this);
this.computProp = ko.computed(function() {
return this.name() + this.status();
}, this);
};

Categories

Resources