angularjs watch for change in multidimensional array - angularjs

i have these array object
$scope.alterations = {
'collar' : { name: 'collar', selected: false, qualitative: 'Perfect' },
'chest' : { name: 'chest', selected: false, qualitative: 'Perfect' },
'shoulder' : { name: 'shoulder', selected: false, qualitative: 'Perfect' },
'waist' : { name: 'waist', selected: false, qualitative: 'Perfect' },
'hips' : { name: 'hips', selected: false, qualitative: 'Perfect' },
'sleeve' : { name: 'sleeve', selected: false, qualitative: 'Perfect' },
'biceps' : { name: 'biceps', selected: false, qualitative: 'Perfect' },
'wrist' : { name: 'wrist', selected: false, qualitative: 'Perfect' },
'length' : { name: 'length', selected: false, qualitative: 'Perfect' },
};
// watch alterations for changes
$scope.$watch('alterations|filter:{selected:true}', function (nv) {
$scope.alter = nv.map(function (alterations) {
return alterations;
}); }, true);
what do i need to change in my filter if i want to only get areas with selected:true in the array?
i got these error for the map method
TypeError: Object #<Object> has no method 'map'
update :
before this its working with these array structure :
$scope.alterations = [
{ name: 'collar', selected: false, qualitative: 'Perfect' },
{ name: 'chest', selected: false, qualitative: 'Perfect' },
{ name: 'shoulder', selected: false, qualitative: 'Perfect' },
{ name: 'waist', selected: false, qualitative: 'Perfect' },
{ name: 'hips', selected: false, qualitative: 'Perfect' },
{ name: 'sleeve length', selected: false, qualitative: 'Perfect' },
{ name: 'biceps', selected: false, qualitative: 'Perfect' },
{ name: 'wrist', selected: false, qualitative: 'Perfect' },
{ name: 'shirt length', selected: false, qualitative: 'Perfect' }
];

Give this js fiddle a try, it's using your new data structure. http://jsfiddle.net/8mXD7/ I've included the change below. See the jsfiddle for the full code.
// watch alterations for changes
$scope.$watch('alterations|filter:{selected:true}', function (nv, ov, scope) {
$scope.alter = [];
angular.forEach(nv, function (value, key) {
if (value.selected == true) {
this.push(value);
}
}, $scope.alter);
}, true);
I got rid of the map, and replaced it with a angular.forEach. This also means you don't need the reference to the full jquery library, and you can just use the built in jqlite.
UPDATED WITH ALTERNATE
Here is an alternate approach with a custom filter function. Notice you need to register the filter with the moddule and update your ng-app to point to the new module.
http://jsfiddle.net/TpM4T/ - see the jsfiddle for the full source, this code is different than the code used above.
angular.module('example', []).
filter('customFilter', function () {
return function (arr) {
var alter = [];
angular.forEach(arr, function (value, key) {
if (value.selected == true) {
this.push(value);
}
}, alter);
return alter;
}
});
UPDATED WITH ANOTHER ALTERNATE
This approach uses the filter service, and actually prevents one of the NAIVE array copies.
http://jsfiddle.net/Qxew8/ - this example demonstrates just a regular function that could be used as a function or a filter.
angular.module('example', []).
filter('customFilter', function () {
return makeArrayOfSelected
});
function makeArrayOfSelected(arr) {
var alter = [];
angular.forEach(arr, function (value, key) {
if (value.selected == true) {
this.push(value);
}
}, alter);
return alter;
};
So in the watch it just calls the filter service:
// watch alterations for changes
$scope.$watch('alterations', function (nv, ov, scope) {
$scope.alter = $filter("customFilter")(nv);
}, true);

Related

Highchart not rendering inside a ajax function angularjs

Highchart is not rendering data from the ajax call. If i used outside $http function with static data the highchart is rendering. The high chart is not triggering.
html:
<hc-pie-chart title="Browser usage" data="pieData">Placeholder for pie chart</hc-pie-chart>
controller:
$scope.homeallpcn = function(){
var url = "homechartall";
var data = "";
$http.get(url).then( function(response) {
$scope.pieData = [{
name: "Cancelled",
y: response.c
}, {
name: "Closed",
y: response.cl,
sliced: true,
selected: true
}, {
name: "Open",
y: response.o
}, {
name: "Rejected",
y: response.r
}]
});
}
$scope.homeallpcn();
service:
mainApp.directive('hcPieChart', function () {
return {
restrict: 'E',
template: '<div></div>',
scope: {
title: '#',
data: '='
},
link: function (scope, element) {
Highcharts.chart(element[0], {
chart: {
type: 'pie'
},
title: {
text: scope.title
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
data: scope.data
}]
});
}
};
})
Please give me suggestion.
Some suggestion :
1 - Do a console.log(response) after the call really show the data ?
2 - Remember pie can't works with string data so response.c, response.o and response.r must be integer or float.

setting a editableCellCondition in a ui-grid inside an angular 1.5 component

I am trying to set rows editable/not editable based on a flag in the data.
I can get this working outside an angular 1.5 component, but can't seem to access row.entity inside a controller in a component.
function memberDisplayCtrl ($scope, memberFactory,uiGridConstants) {
var ctrl = this;
ctrl.people = memberFactory.getMembers();
ctrl.checkStatus = function(ctrl){
// How do I do something like this:
// if (ctrl.row.entity.Status === 'Y') { return 'true'; } else {return 'false';}
};
ctrl.gridOptions = {
enableSorting: true,
enableCellEdit:false,
cellEditableCondition: ctrl.checkStatus(ctrl),
enableHorizontalScrollbar : 0,
enableVerticalScrollbar : 0,
enableColumnMenus: false,
minRowsToShow: ctrl.people.length,
columnDefs: [
{ displayName:'First Name', name: 'fname', enableCellEdit:true },
{ displayName:'Last Name', name: 'lname', enableCellEdit:true },
{ displayName:'Date of Birth', name: 'DOB', type:'date', enableCellEdit:true, cellFilter: 'date:"yyyy-MM-dd"'},
{ displayName:'Address', name: 'address', enableCellEdit:true},
{ displayName:'Status',name: 'Status', enableCellEdit: true}
],
data : ctrl.people
};
}
I'm pretty sure I have a scope problem but can't seem to figure it out. How do I access row.entity? I have an isolated scope inside my controller (since it is part of a component)
plunker here: https://plnkr.co/edit/Wz7gKs
Thanks
just pass a function to cellEditableCondition instead of executing it:
cellEditableCondition: ctrl.checkStatus
and note, that parameter received by that function is not current controller's this (aliased in your case as ctrl), but ui-grid's scope, so I renamed ctrl to scope:
function memberDisplayCtrl ($scope, memberFactory,uiGridConstants) {
var ctrl = this;
ctrl.people = memberFactory.getMembers();
ctrl.checkStatus = function(scope) {
return scope.row.entity.Status === 'Y'
};
ctrl.gridOptions = {
enableSorting: true,
enableCellEdit:false,
cellEditableCondition: ctrl.checkStatus,
enableHorizontalScrollbar : 0,
enableVerticalScrollbar : 0,
enableColumnMenus: false,
minRowsToShow: ctrl.people.length,
columnDefs: [
{ displayName:'First Name', name: 'fname', enableCellEdit:true },
{ displayName:'Last Name', name: 'lname', enableCellEdit:true },
{ displayName:'Date of Birth', name: 'DOB', type:'date', enableCellEdit:true, cellFilter: 'date:"yyyy-MM-dd"'},
{ displayName:'Address', name: 'address', enableCellEdit:true},
{ displayName:'Status',name: 'Status', enableCellEdit: true}
],
data : ctrl.people
};
}
also, I see your commented code:
if (ctrl.row.entity.Status === 'Y') {
return 'true';
}
else {
return 'false';
}
here you intend to return string variable in both cases which will always evaluated as boolean true, you should return boolean:
if (ctrl.row.entity.Status === 'Y') {
return true;
}
else {
return false;
}
which is equal to much shorter version:
return ctrl.row.entity.Status === 'Y';
plunker: https://plnkr.co/edit/KXbJ40?p=preview

Struggling to write a Jasmine testcase for AngularJS

The below code is my controller logic and I want to create a Jasmine test case for it. With $inject I am getting problem how to mock or use the services used in $inject and write a Jasmine test case for below AngularJS controller logic.
(function () {
'use strict';
var controllerId = 'user';
angular.module('app').controller(controllerId, user);
user.$inject = ['$rootScope', 'userService', 'common'];
function user($rootScope, $userService, common) {
var vm = this;
vm.users = [];
vm.sorting = {
column: "UpdatedDate",
order: 0
};
vm.gridHeaders = [
{ title: "UserName", visible: true, sort: true, name: 'UserName', filter: true, type: 'string' },
{ title: "First Name", visible: true, sort: true, name: 'FirstName', filter: true, type: 'string' },
{ title: "Middle Name", visible: true, sort: true, name: 'MiddleName', filter: true, type: 'string' },
{ title: "Last Name", visible: true, sort: true, name: 'LastName', filter: true, type: 'string' },
{ title: "Email Address", visible: true, sort: true, name: 'EmailID', filter: true, type: 'string' },
{ title: "Phone Number", visible: true, sort: true, name: 'PhoneNumber', filter: true, type: 'string' },
{ title: "Mobile Number", visible: true, sort: true, name: 'MobileNumber', filter: true, type: 'string' },
{ title: "City", visible: true, sort: true, name: 'City', filter: true, type: 'string' },
{ title: "Role", visible: true, sort: true, name: 'RoleID', filter: true, type: 'int' },
{ title: "Address", visible: true, sort: true, name: 'Address', filter: true, type: 'string' },
{ title: "UserType", visible: true, sort: true, name: 'UserType', filter: true, type: 'int' },
{ title: "RoleName", visible: true, sort: true, name: 'RoleName', filter: true, type: 'string' }
];
vm.editUser = function (value) {
if (value > 0) {
var request = [{
"PageNumber": vm.pagination.currentPage,
"PageSize": vm.pagination.pageSize,
"SortColumn": vm.sorting.column,
"SortOrder": vm.sorting.order,
"Query": "UserID=" + value
}];
$userService.sendUserID(request);
}
}
vm.loadUserSearchDetails = function () {
//common.showSpinngMan();
var pageConstants = common.preparePageConstants();
vm.pageDropDown = pageConstants.pageDropDown;
vm.pagination = pageConstants.pagination;
loadGrid();
};
vm.loadPageData = function (scenario) {
vm.pagination.currentPage = common.setPagination(scenario, vm.pagination)
loadGrid();
};
//Load grid
var loadGrid = function (data) {
var request = [{
"PageNumber": vm.pagination.currentPage,
"PageSize": vm.pagination.pageSize,
"SortColumn": vm.sorting.column,
"SortOrder": vm.sorting.order,
"Query": ""
// Filters: vm.filterPanel.savedFilter
}];
$rootScope.loading = true;
$userService.getUserDetails(request).then(function (result) {
debugger;
if (!!result) {
vm.users = result.SearchUsers;
vm.pagination.totalRecords = vm.users.length;
vm.pagination.totalPages = Math.ceil(vm.pagination.totalRecords / vm.pagination.pageSize);
}
}).catch(function (result) {
console.log("error load grid");
//$location.path("/error");
}).finally(function () {
$rootScope.loading = false;
})
};
return vm;
}
})();
for the above controller code i have written jasmine testcase by removing injected service userservice and common.js
the new part consists :
//user.$inject = ['$rootScope', 'userService', 'common']; //line removed
function user($rootScope) { // , $userService, common params removed
var vm = this;
vm.users = [];
commented the code relating to $userservice and written jasmine testcase like below and it's working fine.. my question is how write when i inject the other dependencies i.e. 'userservice' 'common'
describe("A suite", function () {
beforeEach(module('app'));
var $controller;
var mockServiceDepedency;
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
it("testing 5", function () {
var $rootScope = {};
var controller = $controller('user', { $rootScope: $rootScope });
expect(controller.users).not.toBeNull();
expect(controller.users).toEqual([]);
expect(controller.sorting.column).toEqual("UpdatedDate");
expect(controller.sorting.order).toEqual(0);
expect(controller.gridHeaders[0]).toEqual({ title: "UserName", visible: true, sort: true, name: 'UserName', filter: true, type: 'string' });
expect(controller.pageDropDown).not.toBeNull();
expect(controller.pageDropDown).not.toBeNull();
expect(controller.loadUserSearchDetails.pageConstants).not.toBeNull();
});
});

How to share code in angular js (concept of code resuability in angular js?

i am new to angular js and i want to share and make certain codes reusable. i have tried to do that using services and factory. But i am getting error.
'use strict';
angular.module('myApp.ctrls')
.controller('Ctrl_HubStockOnHandMode', function($http, $scope, reportService) {
$scope.HubStockOnHandModeGridOptions = {
dataSource: {
type: "jsonp",
transport: {
read: function(e) {
reportService.WebAPI('abc/BIUMo', {
EnvironmentCode:'JMVH',
OrderBy: getOrderBy(e.data.sort)
}).then(function (d) {
$scope.data = d;
e.success(d.Data);
});
}
},
serverPaging: true,
serverSorting: true
},
height:config.GridHeight,
scrollable:true,
sortable: {
mode: "single",
allowUnsort: true
},
filterable: {
extra: false,
operators: {
string: {
startswith: "Starts with",
eq: "Is equal to",
neq: "Is not equal to",
contains: "Contains"
}
}
},
pageable: false,
columns: [
{
field: "RowNumber"
,title: "No."
,width: "50px"
,sortable:false
,filterable: false
},
{
field: 'ItemCTSH'
,title:'Item'
,template: "<div kendo-tooltip title='#= ItemCT #' > #= ItemCTSH # </div>"
,filterable: {
ui: itemFilter
}
},
]
};
}
//Get Item List
$http.get('http://webapi.dashboard.hcmisonline.org/api/OID_WebApi/IssuedItemList')
.success(function (data) {
$scope.items = data.Data;
});
function itemFilter(element) {
element.kendoAutoComplete({
dataSource: $scope.items
});
}
}
});
I want to reuse the functions like the Get item. i have other pages/grids that use exactly this code, except changing the environment code
how to i solve this issue?
thanks

get checkbox group values in angular watch

when tick on each checkbox, i can get all the checked values.
i want to put these values to their respective group.
here are my expected result :
{
'pattern' : ["Plain","Self Design"],
'colour' : ["Blue","Grey"]
}
im using angular $watch to get the selected values.
$scope.$watch('filters|filter:{selected:true}', function (nv, ov, scope) {
$scope.filter_selected = [];
angular.forEach(nv, function (value) {
angular.forEach(value.options, function (v, k) {
if (v.selected == true) {
this.push(v.name);
}
}, $scope.filter_selected);
});
}, true);
here is the full code in fiddle
UPDATE:
i manage to get my expected result with these code :
$scope.$watch('filters|filter:{selected:true}', function (nv, ov, scope) {
$scope.filter_selected = {pattern: [], colour: []};
angular.forEach(nv, function (value) {
if (value.name == 'pattern') {
angular.forEach(value.options, function (v, k) {
console.log(this);
if (v.selected == true) {
this.push(v.name);
}
}, $scope.filter_selected.pattern);
}
if (value.name == 'colour') {
angular.forEach(value.options, function (v, k) {
//console.log(this);
if (v.selected == true) {
this.push(v.name);
}
}, $scope.filter_selected.colour);
}
});
updated fiddle
now, how to make my checking part dynamic if i have more groups?
I have updated your code to simplify what you have above, hopefully achieving the outcome you want. I don't really think you need the watch (unless your update requirements are more complicated), but you should be able to build upon this never the less.
http://jsfiddle.net/j35zt/
The controller code was simplified as follows:
app.controller('FilterCtrl', function ($scope, $http) {
$scope.filters = [
{ name: 'pattern', placeholder: 'pattern',
options: [
{ name: 'Plain', selected: false },
{ name: 'Self Design', selected: false },
{ name: 'Check', selected: false },
{ name: 'Stripe', selected: false },
{ name: 'Print', selected: false }
]},
{ name: 'colour', placeholder: 'colour',
options: [
{ name: 'White', selected: false },
{ name: 'Blue', selected: false },
{ name: 'Grey', selected: false }
]}
];
$scope.updateOutput = function() {
$scope.filter_selected = {};
angular.forEach($scope.filters, function(f) {
$scope.filter_selected[f.name] = [];
angular.forEach(f.options, function(o){
if(o.selected){
$scope.filter_selected[f.name].push(o.name);
}
});
});
}
});
Just note, that the view also needed to be changed to match the controller. Basically ng-change is the sole cause of the updating.

Resources