Angular ui-grid :dropdown with multiple select - angularjs

I am trying to use multiple select in anguler-ui-grid but get error:
TypeError: value.forEach is not a function
at writeNgOptionsMultiple [as writeValue] (angular.js:26579)
at ngModelCtrl.$render (angular.js:28680)
at Object.ngModelWatch (angular.js:25493)
at Scope.$digest (angular.js:15888)
at angular.js:16091
at completeOutstandingRequest (angular.js:5552)
at angular.js:5829(anonymous function) # angular.js:12520(anonymous function) # angular.js:9292Scope.$digest #
angular.js:15914(anonymous function) #
angular.js:16091completeOutstandingRequest # angular.js:5552(anonymous
function) # angular.js:5829
Here is the code: The only change from the official template is the "multiple" attribute in the dropdown template tpl
var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.edit']);
app.controller('MainCtrl', ['$scope', function ($scope) {
var myData = [
{
"firstName": "Cox",
"lastName": "Carney",
"employed": true
},
{
"firstName": "Lorraine",
"lastName": "Wise",
"employed": false
},
{
"firstName": "Nancy",
"lastName": "Waters",
"employed": false
}
];
var dropDownArray = [
{ id: 'Gabi', firstName: 'Gabi' },
{ id: 'Gabriel', firstName: 'Gabriel' }];
$scope.msg = "hello shit";
var tpl = '<div>\
<form\
name="inputForm">\
<select multiple\
ng-class="\'colt\' + col.uid"\
ui-grid-edit-dropdown\
ng-model="MODEL_COL_FIELD"\
ng-options="field[editDropdownIdLabel] as field[editDropdownValueLabel] CUSTOM_FILTERS for field in editDropdownOptionsArray">\
</select>\
</form>\
</div>';
$scope.gridOptions = { data: myData,
columnDefs: [{ field: 'firstName', displayName: 'First Name', width: 190,
editableCellTemplate: tpl,
editDropdownValueLabel: 'firstName',
editDropdownOptionsArray: dropDownArray },
{ field: 'lastName', displayName: 'Last Name', width: 180 },
{ field: 'employed', displayName: 'employed?', width: 180 }]}
}]);

I ran into the same problem - a tough one because it works with angular 1.2 but not with 1.4.
The solution for me was that the initial field value has to be an array, not a string.
So your data must look like this:
var myData = [
{
"firstName": ["Cox"],
"lastName": "Carney",
"employed": true
},
{
"firstName": ["Lorraine"],
"lastName": "Wise",
"employed": false
},
{
"firstName": ["Nancy"],
"lastName": "Waters",
"employed": false
}
];
And the error should go away.

Related

Row span in UI Grid Angular JS

I am trying to divide a Row into two ie. Row Span in Angular JS UI Grid. I am not able to find how to do this.I need different color schemes for rows within the rows of the UI grid. Can anyone please help me with this and give me some related fiddle or plunker to refer. Thanks in advance.
I have a RowSpan hack, suitable for my need, not necessarily suitable for every case: I use position:absolute on the top row's cell and display:none on the spanned rows' cells. See http://plnkr.co/edit/TiQFJnyOvVECOH2RL4ha
Everything is in the ng-style in the cell template, which uses a spanCompany attribute to know the number of rows to override. We have to calculate the height and width since we are position:absolute. This also means the width has to be expressed in px, not %.
ng-style extract:
ng-style="{
height:21*row.entity.spanCompany+'px',
width:col.width+'px',
position:'absolute',
display:row.entity.spanCompany==0?'none':'block'
}"
Full code:
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.data = [
{
"firstName": "Cox",
"lastName": "Carney",
"company": "Enormo has a rather long company name that might need to be displayed in a tooltip",
"spanCompany":2,
"employed": true
},
{
"firstName": "Lorraine",
"lastName": "Wise",
"company": "Enormo",
"spanCompany":0,
"employed": false
},
{
"firstName": "Nancy",
"lastName": "Waters",
"company": "Fuelton",
"spanCompany":1,
"employed": false
}
];
$scope.gridOptions = {
columnDefs: [
{ name: 'firstName', width: '20%' },
{ name: 'lastName', width: '20%' },
{ name: 'company', width: '200',
cellTemplate: '<div class="ui-grid-cell-contents wrap" title="TOOLTIP" ng-style="{ height:21*row.entity.spanCompany + \'px\', width:col.width+\'px\', position:\'absolute\', display:row.entity.spanCompany==0?\'none\':\'block\', borderStyle:\'dotted\', borderWidth:\'1px\'}" >{{COL_FIELD CUSTOM_FILTERS}}</div>'
},
{ name: 'employed', width: '30%' }
],
data: 'data',
rowHeight: 21
};
}]);

UI Grid add editable row

I wanted to add a new row into my existing grid. Also, the row which is getting pushed should be editable.
I tired below code and the row is getting added, But I wanted editable fields to be added
$scope.addNewItem=function() {
$scope.data.push( { name: 'Test add ' });
};
Can someone help me for the same.
Try this sample
Update
This is full source code
<!doctype html>
<html ng-app="app">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-touch.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-animate.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/csv.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/pdfmake.js"></script>
<script src="http://ui-grid.info/docs/grunt-scripts/vfs_fonts.js"></script>
<script src="http://ui-grid.info/release/ui-grid-unstable.js"></script>
<link rel="stylesheet" href="http://ui-grid.info/release/ui-grid-unstable.css" type="text/css">
</head>
<body>
<div ng-controller="MainCtrl">
<div ui-grid="{ data: data, columnDefs: columnDefs,enableRowSelection: true,
enableSelectAll: true,
enableFiltering: true, }" class="grid" ui-grid-selection ui-grid-edit ui-grid-cellnav></div>
<button ng-click="addNewItem()" > ADD item</button>
<button ng-click="insertNewItem()" > Insert item</button>
</div>
<script src="app.js"></script>
</body>
</html>
controller and module code
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.edit','ui.grid.cellNav']);
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.data = [
{ name: 'Bob', title: 'CEO' },
{ name: 'Frank', title: 'Lowly Developer' }
];
$scope.columnDefs = [
{name: 'name', cellEditableCondition:true},
{name: 'title', cellEditableCondition:true}
];
$scope.addNewItem=function()
{
$scope.data.push( { name: 'Test add ', title: 'Test add' });
};
$scope.insertNewItem=function()
{
$scope.data.splice(1, 0, { name: 'Test insert ', title: 'Test insert' });
};
}]);
Updated Demo in plunkr
in controller
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.addData = function() {
var n = $scope.gridOpts.data.length + 1;
$scope.gridOpts.data.push({
"firstName": "New " + n,
"lastName": "Person " + n,
"company": "abc",
"employed": true,
"gender": "male"
});
};
var columnDefs1 = [
{ name: 'firstName' },
{ name: 'lastName' },
{ name: 'company' },
{ name: 'gender' }
];
var data1 = [
{
"firstName": "Cox",
"lastName": "Carney",
"company": "Enormo",
"gender": "male"
},
{
"firstName": "Lorraine",
"lastName": "Wise",
"company": "Comveyer",
"gender": "female"
},
{
"firstName": "Nancy",
"lastName": "Waters",
"company": "Fuelton",
"gender": "female"
},
{
"firstName": "Misty",
"lastName": "Oneill",
"company": "Letpro",
"gender": "female"
}
];
$scope.gridOpts = {
columnDefs: columnDefs1,
data: data1
};
}]);
in html
<body>
<div ng-controller="MainCtrl">
<button type="button" id="addData" class="btn btn-success" ng-click="addData()">Add Data</button>
<div id="grid1" ui-grid="gridOpts" class="grid"></div>
</div>
$scope.gridOpts.data.push({
"firstName": "New " + n,
"lastName": "Person " + n,
"company": "abc",
"employed": true,
"gender": "male",
enableCellEdit: true,
});
add enableCellEdit: true, this to enable the

Angularjs UI Grid Totals per Row inside the row

{{ HelloWorld }}
I'm trying to access the values from other columns in the same row in angular-ui-grid. I have two question that are related.
How can I add the values from several columns in the same row to get a Total?
How can I use the row index to pass it as a parameter and remove the current row?
As you can see in the above image, the Totals that I'm looking for are only related to the integer values and not the initial string.
Also the Button with an X should delete the row when clicked. The rows are included in the grid dynamically.
I've gone through the UI Grid Tutorial but the examples don't show how to accomplish either of my questions.
My footer is working fine. It's configure to give a total but by column in the entire set of rows:
Here's a little bit of my code with what I've found so far:
var removeTemplate = '<button type="button" class="grid-remove btn btn-default btn-sm"><span class="glyphicon glyphicon-remove" aria-hidden="true" ng-click="removeRow($event, row.entity)"></span></button>';
$scope.gridAccountableHours = {
enableCellEditOnFocus: true,
showColumnFooter: true
};
$scope.gridAccountableHours.columnDefs = [
{ name: "contractCode", displayName: ""},
{ name: "hours1", displayName: "1", type: "number" },
{ name: "hours2", displayName: "2", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours3", displayName: "3", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours4", displayName: "4", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours5", displayName: "5", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours6", displayName: "6", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours7", displayName: "7", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours8", displayName: "8", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours9", displayName: "9", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours10", displayName: "10", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours11", displayName: "11", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours12", displayName: "12", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours13", displayName: "13", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours14", displayName: "14", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "hours15", displayName: "15", type: "number", aggregationType: uiGridConstants.aggregationTypes.sum },
{ name: "total", displayName: "Total" },
{ name: "remove", displayName: "", cellTemplate: removeTemplate }
];
$scope.removeRow = function ($event, entity) {
$event.stopPropagation();
$scope.gridAccountableHours.data.splice($scope.gridAccountableHours.data.indexOf(entity), 1);
};
I appreciate your time.
Totalling across the grid you could do with a function on the gridRow.
$scope.gridAccountableHours.forEach(function(rowEntity) {
rowEntity.total = function() {
var total = 0;
for( var 1 = 1; i++; i<=15 ){
total += this['hours'+i];
}
};
});
Your total column def should automatically bind to this total function. Refer http://ui-grid.info/docs/#/tutorial/106_binding
For the delete button, you're missing the appScope, refer http://ui-grid.info/docs/#/tutorial/305_appScope
Your template ng-click should be:
ng-click="grid.appScope.removeRow($event, row.entity)"

EXTJS 5.1 VERY SIMPLE TreeStore from JSON

I have looked around but I still don't understand how to create treestore properly.
I have this very simple json that I get from a server:
{
"Results": [
{
"name": "John",
"age": 23,
"cars": [
{
"name": "Clio",
"brand": "Renault"
},
{
"name": "Class S",
"brand": "Mercedes"
}
]
},
{
"name": "Michel",
"age": 42,
"cars": [
{
"name": "Qashqai",
"brand": "Nissan"
}
]
}
]
}
I have my two models:
Ext.define('Person', {
extend: 'Ext.data.Model',
fields: [ 'name', 'age']
});
Ext.define('Car', {
extend: 'Ext.data.Model',
fields: [ 'name', 'brand']
});
Now I know that I have to create a tree store, but in all example that I have seen, there is always a "children" property in the json, which I don't have.
How to create a tree store with the following json?
Thanks a lot in advance :) !!
You could always build the correct formatted object for the data like the following:
Ext.application({
name: 'Fiddle',
launch: function () {
var myTreeData = {
"Results": [{
"name": "John",
"age": 23,
"cars": [{
"name": "Clio",
"brand": "Renault"
}, {
"name": "Class S",
"brand": "Mercedes"
}]
}, {
"name": "Michel",
"age": 42,
"cars": [{
"name": "Qashqai",
"brand": "Nissan"
}]
}]
},
modifiedData = {
expanded: true,
children: []
};
myTreeData.Results.forEach(function (result) {
var newChildrenArray = [];
result.cars.forEach(function (car) {
var newChild = {
text: car.name,
leaf: true
};
newChildrenArray.push(newChild);
});
var person = {
text: result.name,
leaf: (newChildrenArray.length > 0 ? false : true),
children: newChildrenArray
};
modifiedData.children.push(person);
});
var store = Ext.create('Ext.data.TreeStore', {
root: modifiedData
});
Ext.create('Ext.tree.Panel', {
title: 'Simple Tree',
width: 200,
height: 150,
store: store,
rootVisible: false,
renderTo: Ext.getBody()
});
}
});
Demo here: https://fiddle.sencha.com/#fiddle/j05

extjs parsing nested json in template

Trying (unsuccessfully) to display data from nested json.
JSON might look something like:
{
"contacts": [
{
"id": "1",
"client_id": "135468714603",
"addresses": [
{
"id": "1",
"contact_id": "1",
"address_id": "16",
"address": {
"0": {
"id": "16",
"address": "123 Some Rd",
"address2": "",
"city": "Toen",
"state": "VS",
"zip_code": "11111",
"country": "USA"
}
}
},
{
"id": "6",
"contact_id": "1",
"address_id": "26",
"address": {
"0": {
"id": "26",
"address": "1 Other Road",
"address2": "",
"city": "Twn",
"state": "BD",
"zip_code": "11112",
"country": "USA"
}
}
}
]
},
{
"id": "10",
"client_id": null,
"addresses": [
{
"id": "8",
"contact_id": "10",
"address_id": "28",
"address": {
"0": {
"id": "28",
"address": "54 Road",
"address2": "",
"city": "TWND",
"state": "TT",
"zip_code": "11113",
"country": "USA"
}
}
},
{
"id": "9",
"contact_id": "10",
"address_id": "29",
"is_mailing_address": "0",
"is_primary_address": "0",
"display_priority": "0",
"address": {
"0": {
"id": "29",
"address": "6 Road",
"address2": "",
"city": "TOEOEOWN",
"state": "PY",
"zip_code": "11116",
"country": "USA"
}
}
},
{
"id": "10",
"contact_id": "10",
"address_id": "30",
"address": {
"0": {
"id": "30",
"address": "PO Box 9",
"address2": "",
"city": "TOYN",
"state": "GF",
"zip_code": "11118",
"country": "USA"
}
}
}
]
},
{
"id": "11",
"client_id": null,
"contact_id": "11",
"addresses": [
{
"id": "11",
"contact_id": "11",
"address_id": "33",
"is_mailing_address": "0",
"is_primary_address": "0",
"display_priority": "0",
"address": {
"0": {
"id": "33",
"address": "4 Street",
"address2": "",
"city": "TEOIN",
"state": "TG",
"zip_code": "11119",
"country": "USA"
}
}
}
]
}
]
}
I've tried mapping model fields to what I need (e.g. contacts model > addresses field > mapping: addresses), but this doesn't work because I'd need to map to addresses[0].address[0] to get the data which obviously discards the other addresses.
I've also tried playing around with associations, but this appears to be separate models and stores. The idea here is to not make a separate request for the contacts and then their addresses.
I've also tried digging into the json straight in the template (which seemed to be the most straightforward way) e.g. {addresses.address.city} which doesn't work.
The thinking is simple: grab some json, and display different parts of said json in different parts of the app.
The experience has been dreadful.
Can someone explain how to map these nested json items so that they are accessible from a template?
Template:
{
xtype: 'container',
flex: 1,
id: 'mainPanel',
items: [
{
xtype: 'dataview',
hidden: false,
id: 'clientsContacts',
minHeight: 200,
itemSelector: 'div',
itemTpl: [
'{id} | {last_name} | {first_name} | {relationship} | {addresses}'
],
store: 'Contacts'
}
]
}
Store:
Ext.define('MyApp.store.Contacts', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.Contacts'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: false,
storeId: 'Contacts',
model: 'MyApp.model.Contacts',
proxy: {
type: 'ajax',
extraParams: {
id: '',
format: 'json'
},
url: '/api/contacts/', //the json
reader: {
type: 'json',
root: 'contacts'
}
},
listeners: {
load: {
//fn: me.onJsonstoreLoad,
//scope: me
}
}
}, cfg)]);
},
});
Model:
Ext.define('MyApp.model.Contacts', {
extend: 'Ext.data.Model',
uses: [
//'MyApp.model.Client',
//'MyApp.model.contactAddressModel'
],
fields: [
{
name: 'client_id'
},
{
name: 'id'
},
{
name: 'addresses',
mapping: 'addresses'//doesn't work
//mapping: 'addresses[0].address[0]' //works, but only for the first address duh
}
],
});
Using extjs 4.1 via Sencha Architect.
Any help would be greatly appreciated.
Thanks.
I think I got it (hopefully it's correct).
So, create a field for each nested group of data you need. So I have a Contacts model. In that model there are these fields:
id
client_id
addresses //mapped to addresses
address //mapped to addresses.address
then in the template:
<br>
<tpl for="addresses">
id: {id}<br>
addy id: {address_id}<br>
<tpl for="address">
{city} {state}, {zip}<br>
</tpl>
</tpl>
This is what the whole thing looks like:
View
Ext.define('MyApp.view.MyView', {
extend: 'Ext.view.View',
height: 250,
width: 400,
itemSelector: 'div',
store: 'MyJsonStore',
initComponent: function() {
var me = this;
Ext.applyIf(me, {
itemTpl: [
'<br>',
'<tpl for="addresses">',
' id: {id}<br>',
' addy id: {address_id}<br>',
' <b>',
' <tpl for="address">',
' {city} {state}, {zip}<br><br>',
' </tpl>',
' </b>',
'',
'</tpl>',
'',
'<hr>',
''
]
});
me.callParent(arguments);
}
});
Store
Ext.define('MyApp.store.MyJsonStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.Contacts'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
storeId: 'MyJsonStore',
model: 'MyApp.model.Contacts',
data: {
contacts: [
{
id: '1',
client_id: '135468714603',
addresses: [
{
id: '1',
contact_id: '1',
address_id: '16',
address: {
'0': {
id: '16',
address: '123 Some Rd',
address2: '',
city: 'Toen',
state: 'VS',
zip_code: '11111',
country: 'USA'
}
}
},
{
id: '6',
contact_id: '1',
address_id: '26',
address: {
id: '26',
address: '1 Other Road',
address2: '',
city: 'Twn',
state: 'BD',
zip_code: '11112',
country: 'USA'
}
}
]
},
{
id: '10',
client_id: null,
addresses: [
{
id: '8',
contact_id: '10',
address_id: '28',
address: {
id: '28',
address: '54 Road',
address2: '',
city: 'TWND',
state: 'TT',
zip_code: '11113',
country: 'USA'
}
},
{
id: '9',
contact_id: '10',
address_id: '29',
is_mailing_address: '0',
is_primary_address: '0',
display_priority: '0',
address: {
id: '29',
address: '6 Road',
address2: '',
city: 'TOEOEOWN',
state: 'PY',
zip_code: '11116',
country: 'USA'
}
},
{
id: '10',
contact_id: '10',
address_id: '30',
address: {
id: '30',
address: 'PO Box 9',
address2: '',
city: 'TOYN',
state: 'GF',
zip_code: '11118',
country: 'USA'
}
}
]
},
{
id: '11',
client_id: null,
contact_id: '11',
addresses: [
{
id: '11',
contact_id: '11',
address_id: '33',
is_mailing_address: '0',
is_primary_address: '0',
display_priority: '0',
address: {
id: '33',
address: '4 Street',
address2: '',
city: 'TEOIN',
state: 'TG',
zip_code: '11119',
country: 'USA'
}
}
]
}
]
},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'contacts'
}
}
}, cfg)]);
}
});
Model
Ext.define('MyApp.model.Contacts', {
extend: 'Ext.data.Model',
fields: [
{
name: 'id'
},
{
name: 'client_id'
},
{
name: 'addresses',
mapping: 'addresses'
},
{
name: 'address',
mapping: 'address'
}
]
});
I have verified that the above answer does work, but to note for future people, that if you don't specify the name of sub fields, you don't need the 2nd nested template. You can do it with just the first.

Resources