I'm using Angular-Datatables. I need to be able to dynamically create the table based on the data that is being returned. In other words, I do not want to specify the column headers.
Example:
json data:
[
{
"id": "2",
"city": "Baltimore",
"state": "MD",
},
{
"id": "5",
"city": "Boston",
"state": "MA",
},
{
"id": "8",
"city": "Malvern",
"state": "PA",
},
]
Column Headers:
id, city, state
Can someone please help with this?
That is actually a good question! With traditional jQuery dataTables it is not a problem, but we have a different kind of declarative setup with angular dataTables, making it more difficult to separate the various tasks. We can delay the population of data with fromFnPromise, but not prevent the dataTable from being instantiated before we want it. I think I have found a solid solution :
First, to avoid instant initialization remove the datatable directive from the markup and give the <table> an id instead, i.e :
<table id="example" dt-options="dtOptions" dt-columns="dtColumns" />
Then load the data resource, build dtColumns and dtOptions and finally inject the datatable attribute and $compile the <table> using the id :
$http({
url: 'data.json'
}).success(function(data) {
var sample = data[0], dtColumns = []
//create columns based on first row in dataset
for (var key in sample) dtColumns.push(
DTColumnBuilder.newColumn(key).withTitle(key)
)
$scope.dtColumns = dtColumns
//create options
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withOption('data', data)
.withOption('dataSrc', '')
//initialize the dataTable
angular.element('#example').attr('datatable', '')
$compile(angular.element('#example'))($scope)
})
This should work with any "array of objects" resource
Demo -> http://plnkr.co/edit/TzBaaZ2Msd9WchfLDLkN?p=preview
NB: Have cleaned up the example JSON, I guess it was a sample and not meant to be working with trailing commas.
Being faced with the same problem, I actually found an easier to implement and much simpler (and safer because of not using $compile) solution.
The only change needed to be made to the html is the addition of an ng-if:
<table ng-if="columnsReady" datatable="" dt-options="dtOptions" dt-columns="dtColumns"/>
What happens is that angular will delay the creation of this node till columnsReady has any value. So now in your code you can get the data you need, and when you have it, you can just set columnsReady to true and angular will do the rest.
$http({
url: 'data.json'
}).success(function(data) {
var sample = data[0], dtColumns = []
//create columns based on first row in dataset
for (var key in sample) dtColumns.push(
DTColumnBuilder.newColumn(key).withTitle(key)
)
$scope.dtColumns = dtColumns
//create options
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withOption('data', data)
.withOption('dataSrc', '')
//initialize the dataTable
$scope.columnsReady = true;
});
Below code which will give you table dynamically based on data
HTML
<div ng-controller="WithAjaxCtrl as showCase">
<table datatable="" dt-options="showCase.dtOptions" dt-columns="showCase.dtColumns" class="row-border hover"></table>
JS
angular.module('showcase.withAjax',['datatables']).controller('WithAjaxCtrl', WithAjaxCtrl);
function WithAjaxCtrl(DTOptionsBuilder, DTColumnBuilder) {
var vm = this;
vm.dtOptions = DTOptionsBuilder.fromSource('data.json')
.withPaginationType('full_numbers');
vm.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('city').withTitle('City'),
DTColumnBuilder.newColumn('state').withTitle('State')
];
}
data.json
[{
"id": 860,
"city": "Superman",
"state": "Yoda"
}, {
"id": 870,
"city": "Foo",
"state": "Whateveryournameis"
}, {
"id": 590,
"city": "Toto",
"state": "Titi"
}, {
"id": 803,
"city": "Luke",
"state": "Kyle"
},
...
]
Related
Using Datatables with a .json source file, I am trying to manipulate the data before it shows in the table. I'm trying to simply remove spaces and replace with a dash in this example.
There are two ways I understand to do some data manipulation. One is columnDefs the other is using dataSrc and return the data. Both fail when i try to utilize .split or .replace or even .toLowerCase()...
For example, I have columnDefs added like so:
columnDefs: [
{
"render": function ( data, type, row ) {
console.log(data);
var cn = data.split(" ").join("-").toLowerCase();
return cn;
},
"targets": 1
}
],
The console shows:
Uncaught TypeError: data.split is not a function
How do we manipulate the data with replace or the like?
My data looks like:
{
"Licensee": "Whistles for Woods",
"Contact Name": "Bob",
"Street": "2230 Trail",
"Suite / PO Box": 0,
"City": "Alturas",
"ST": "CA",
"Zip Code": 997733,
"Telephone": 0,
"Email Address": "bobc#email.com",
"Website Address": "www.domain.com",
"Fax": "No fax",
"Products": "whistle with custom logo",
"Categories": "Miscellaneous"
},
As discussed in the comments
We just want to make sure that we are indeed manipulating strings and not any other data type. So in this case we would change the code to look something like this:
columnDefs: [
{
"render": function ( data, type, row ) {
if(typeof data === 'string'){
//only if string manipulate
data = data.split(" ").join("-").toLowerCase();
}
// OR data = data.toString(); whichever is more convenient!
return data;
},
"targets": 1
}
],
We're building a frontend project for a web app that communicates with a backend written by another team. Some of the developers work on both projects, and have better understanding of changes to the backend and response fields coming back.
Recently we had portions of frontend break as they made changes in parts of the app based on changes to the backend without updating the logic in all places. To mitigate this I want to put in place a concept of a mask/template that all response data would be curated through. That way the rest of the members on the team who're not as familiar with the backend can notice/address these bugs.
To do so, I'm considering using JSON Schema. Instead of simply validating, however, I want to parse the backend data through it (removing the fields not present in the schema). This way the developer making changes in the frontend in response to a backend change would also need to update this template, therefore triggering a test failure until all logic using this schema is updated (not just the logic he touched). I'm playing with https://www.npmjs.com/package/jsonschema, but it doesn't seem to have a way to remove excess fields, just test for them.
Within JSON Schema, I can also set additionalProperties flag. However, it has 2 problems with it:
It doesn't cause the validator to remove the fields, it simply dumps them to error array
It needs to be set individually at each nested level, therefore I need to traverse the entire JSON structure, at which point I basically end up writing my own parser/validator.
Perhaps validator is not the right tool for this, but that's all I'm finding when searching for JSON schema parsers. Can someone guide me in the right direction so that I don't reinvent the wheel? It sounds like this functionality is very similar to what a validator already does and I would rather do this processing in the same pass.
Found a validator that does what I want: https://github.com/acornejo/jjv. It has removalAdditional flag that I can set, here is a quick test I did:
var jjv = require('jjv')();
var addressSchema = {
"id": "address",
"type": "object",
"properties": {
"lines": {
"type": "array",
"items": {"type": "string"}
},
"zip": {"type": "string"},
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["country"]
};
var schema = {
"id": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"address": {"$ref": "address"},
"votes": {"type": "integer", "minimum": 1}
}
};
var p = {
"name": "Barack Obama",
"address": {
"lines": [ "1600 Pennsylvania Avenue Northwest" ],
"zip": "DC 20500",
"city": "Washington",
"foobar": "baz",
"country": "USA"
},
"a": {
"b": 1,
"c": 2
},
"votes": "lots",
"stuff": "yes"
};
jjv.addSchema('address', addressSchema);
jjv.addSchema('schema', schema);
jjv.defaultOptions.checkRequired = true;
jjv.defaultOptions.removeAdditional = true;
console.log(jjv.validate('schema', p));
console.log(p);
And a response:
{ validation: { votes: { type: 'integer' } } }
{ name: 'Barack Obama',
address:
{ lines: [ '1600 Pennsylvania Avenue Northwest' ],
zip: 'DC 20500',
city: 'Washington',
country: 'USA' },
votes: 'lots' }
I am attempting to create a Google map with data from two separate json files. I'm trying to use jquery/javascript to combine the two files and then process the resulting array of objects through the Google Maps API.
I've tried $.extend, $.merge, concat, and I've even tried pushing the data into an empty array, but in each case only the first set of data is appearing on the map (although I can see both sets of data separately if I display them with console.log).
I must be doing something fundamentally wrong, but I'm not seeing it. The relevant part of my code is as follows (with the things I've tried commented out). Any suggestions would be most appreciated.
j$.when(
j$.getJSON('mapData1.js'),
j$.getJSON('mapData2.js')
).done(function(data1, data2) {
var d1 = data1;
var d2 = data2;
var d3 = [];
d3.push(d1[0]);
d3.push(d2[0]);
//var d3 = j$.extend({},d1,d2);
//var d3 = j$.merge(d1,d2);
//var d3 = d1.concat(d2);
var data = d3[0];
//code to process data with Google Maps API
});
My json files look like this (but with many more items):
[
{
"ID": "a001a000002o4iZAAQ",
"NAME": "Atlanta",
"Address": "123 State Street",
"City": "Atlanta",
"StateAbbreviation": "GA",
"SF": "",
"LeaseExpiration": "8/31/2012",
"Occupancy": "2",
"Country": "USA",
"Address2": "",
"Lat": "33.7863317",
"Lng": "-84.3836873",
"Type": "loc",
"Color": "red"
}
]
you can use concat()
var array1 = [{
"ID-1": "a001a000002o4iZAAQ",
"NAME-1": "Atlanta",
"Address-1": "123 State Street",
"City-1": "Atlanta",
"StateAbbreviation-1": "GA",
"SF-1": "",
"LeaseExpiration-1": "8/31/2012",
"Occupancy-1": "2",
"Country-1": "USA",
"Address2-1": "",
"Lat-1": "33.7863317",
"Lng-1": "-84.3836873",
"Type-1": "loc",
"Color-1": "red"
}];
var array2 = [{
"ID-2": "a001a000002o4iZAAQ",
"NAME-2": "Atlanta",
"Address-2": "123 State Street",
"City-2": "Atlanta",
"StateAbbreviation-2": "GA",
"SF-2": "",
"LeaseExpiration-2": "8/31/2012",
"Occupancy-2": "2",
"Country-2": "USA",
"Address2-2": "",
"Lat-2": "33.7863317",
"Lng-2": "-84.3836873",
"Type-2": "loc",
"Color-2": "red"
}];
var array3 = array1.concat(array2);
alert(JSON.stringify(array3));
I am reading the below json value from a module.js
.controller('home.person',['$scope','$filter','personResource',function($scope,$filter,personResource) {
$scope.searchPerson = function() {
var params = $scope.search || {};
params.skip=0;
params.take =10;
$scope.personDetails =
{
"apiversion": "0.1",
"code": 200,
"status": "OK",
"mydata": {
"myrecords": [
{
"models": [
{
"name": "Selva",
"dob": "10/10/1981"
}
],
"Address1": "ABC Street",
"Address2": "Apt 123",
"City": "NewCity1",
"State": "Georgia"
},
{
"models": [
{
"name": "Kumar",
"dob": "10/10/1982"
}
],
"Address1": "BCD Street",
"Address2": "Apt 345",
"City": "NewCity2",
"State": "Ohio",
"Country":"USA"
},
{
"models": [
{
"name": "Pranav",
"dob": "10/10/1983"
}
],
"Address1": "EFG Street",
"Address2": "Apt 678",
"City": "NewCity3",
"State": "NewYork",
"Country":"USA",
"Zipcode" :"123456"
}
]
}
}
}
}])
Now i am able to statically build the UX. But my each record set's key value pair count is different. So i want to build my html dynamically as per the current record set's count.Country & Zipcode is not exist in all records so i need to build dynamically the build and populate the html output.Most of the time, my json output is dynamic. Instead of persondetails, i may get the json output of a product details instead of PersonDetails.
<div ng-show="personDetails.mydata.myrecords.length > 0" ng-repeat="recordSingle in personDetails.mydata.myrecords">
<div >
<span >Address1: {{recordSingle.Address1}}</span>
<span >Address2: {{recordSingle.Address2}}</span>
<span>City: {{recordSingle.City}}</span>
<span>State: {{recordSingle.State}}</span>
<span>Country: {{recordSingle.Country}}</span>
<span>Zipcode: {{recordSingle.Zipcode}}</span>
</div>
</div>
One way is to use ng-if statement, for the optional span elements:
<span ng-if="recordSingle.Address1">Address1: {{recordSingle.Address1}}</span>
[Update #1: updated based on revised comments to question]
[Update #2: fixed typos in function and included plunkr]
I now understand that you want to dynamically build the display objects based on properties from the JSON object. In this case, I would iterate through the properties of the object. I would use a function to produce this array of properties for each object so that you can filter out any prototype chains. I would also remove out any unwanted propoerties, such as the internal $$hashKey and perhaps the array objects e.g.
In your controller:
$scope.getPropertyNames = getPropertyNames;
function getPropertyNames(obj) {
var props = [];
for (var key in obj) {
if (obj.hasOwnProperty(key) && !angular.isArray(obj[key]) && key !== '$$hashKey') {
props.push(key);
}
}
return props;
}
Then in your HTML view:
<div ng-repeat="record in personDetails.mydata.myrecords">
<div ng-repeat="prop in getPropertyNames(record)">
<span ng-bind="prop"></span>: <span ng-bind="record[prop]"></span>
</div>
</div>
This works for me... see this plunker. It is displaying each of the properties of the object in the array dynamically (you could have any property in the object). Is this not what you are trying to achieve?
Consider a JSON like this:
[{
"type": "person",
"name": "Mike",
"age": "29"
},
{
"type": "person",
"name": "Afshin",
"age": "21"
},
{
"type": "something_else",
"where": "NY"
}]
I want to search in the JSON value with a key (for example type='person') and then select a whole object of matched item in JSON. For example when I search for type='person' I expect this value:
[{
"type": "person",
"name": "Mike",
"age": "29"
},
{
"type": "person",
"name": "Afshin",
"age": "21"
}]
Because it's a really big JSON value, I don't want to do a brute-force search in all nodes, so I think the only way is using Regular Expressions but I don't know how can I write a Regex to match something like above.
I'm using NodeJs for the application.
Using underscore.js#where:
var results = _(yourObject).where({ type: 'person' })
If your data set is very very big [e.g. 10k or so], consider filtering / paginating stuff server side.
Plain javascript :
var results = dataset.filter(function(p) {
if(p.type == 'person')
return true;
});
If the requirement is to scan multiple times through the collection, the following one time construction overhead might be of worth.
Use hashing based on values of type.Convert the current data structure to hash map.
var hashMap ={
};
hashMap['person'] =[{},{}];
Hope this helps you.
Use
$.grep(jsonarrayobj,function(n, i){
if(n.type==="person")
{}
})