How to bind template to object in array by property value? - angularjs

I'm probably looking for a directive of some sort, right?
//JS
$rootScope.cats = [
{ sort:0, value:'ABY', label:'Abyssinian' },
{ sort:1, value:'RGD', label:'Ragdoll' },
{ sort:2, value:'RBL', label:'Russian Blue' },
{ sort:3, value:'OCT', label:'Ocicat' }
];
//HTML
{{cats['ABY'].label}} //This obviously doesn't work. Is there something in Angular that would?

Try to find the proper object in controller, for example:
$scope.cats = [
{ sort: 0, value: 'ABY', label: 'Abyssinian' },
{ sort: 1, value: 'RGD', label: 'Ragdoll' },
{ sort: 2, value: 'RBL', label: 'Russian Blue' },
{ sort: 3, value: 'OCT', label: 'Ocicat' }
];
$scope.selectedCat = _.find($scope.cats, function (cat) {
return cat.value == 'OCT';
});
And put this into your layout:
{{selectedCat.label}}
NB Lodash library is used to find the proper cat.

This can be a candidate for a custom filter. See DEMO
app.filter('label', function(){
return function(arr, value) {
var cats;
if(arr) {
cats = arr.filter(function(elem) {
return elem.value == value;
});
}
return cats && cats.length > 0 ?
cats[0].label : 'Not Found';
}
});

Related

Multi Level JSON Filter

So I have this json:
this.state = {
projects: [{
id: 10,
name: "Project 10",
runTimes: [{
id: 186,
name: "Do Homeworks",
start: "2020-W01",
end: "2020-W09",
project: 10,
users: [{
id: 1,
name: "Sander Cokart",
runTime: [
186
]
}]
}],
hidden: false
}, ]
}
And I wish to filter based on runTimes.start & end,
I have already tried this:
const filtered = array.filter((project) => {
if (!project.hidden) {
if (project.runTimes.filter((runTime) => {
if (moment(runTime.start).isSameOrAfter(context.searchFrom) &&
moment(runTime.end).isSameOrBefore(context.searchTo)) {
return runTime;
}
}).length > 0) {
return project;
}
}
});
sadly it doesn't work the second a second RunTime exists inside a project object RunTimes array.
anyone have an idea?
The filter functions are just a bit off. I'd argue the if statement wrapped around the filter is confusing, I'd go for something simpler. This is working for me:
const result = array.projects.filter((project) => {
return !project.hidden && project.runTimes.filter(runTime => {
return moment(runTime.start).isSameOrAfter("2020-W01") &&
moment(runTime.end).isSameOrBefore("2020-W12")
})
});

PrimeNG p-table Lazy loading and Multi Sort - Goes in Loop - Maximum call stack size exceeded

Stackblitz: https://stackblitz.com/edit/primeng-p-table-multisort
Config:
"#angular/cli": "~7.0.2",
"primeng": "7.0.5",
I have a PrimeNG p-table implemented with lazy loading. Need multi column sort added to it.
Sample code from above Stackblitz link.
<p-table [columns]="cols" [value]="cars1" [lazy]="true" [lazyLoadOnInit]="false" (onLazyLoad)="loadList($event)" sortMode="multiple" [multiSortMeta]="multiSortMeta">
This works properly if its single sort mode.
Getting error as ERROR RangeError: Maximum call stack size exceeded.
It should be a simple implementation but not able to understand what is missing here or this is not supported by PrimeNG.
Any help is appreciated.
This issue was because of this.cdRef.detectChanges(); Here is why
loadList is binded to (onLazyLoad)="loadList($event)" in HTML.
PrimeNg calls that event every time when paging, sorting, and filtering happens. So, when we are loading and adding sorting events it keeps calling. And Angular change detection also called every time, that leads to error ERROR RangeError: Maximum call stack size exceeded
loadList($event: any = {}) {
this.cars1 = [
{
vin: "a1653d4d",
brand: "VW",
year: 1998,
color: "White",
price: 10000
},
{
vin: "ddeb9b10",
brand: "Mercedes",
year: 1985,
color: "Green",
price: 25000
}
];
this.cdRef.detectChanges(); // this is the issue
}
modified
ngOnInit() {
this.cols = [
{ field: "vin", header: "Vin" },
{ field: "year", header: "Year" },
{ field: "brand", header: "Brand" },
{ field: "color", header: "Color" }
];
this.multiSortMeta = [
{ field: "year", order: 1 },
{ field: "brand", order: -1 }
];
this.loadList();
}
loadList($event: any = {}) {
this.cars1 = [
{
vin: "a1653d4d",
brand: "VW",
year: 1998,
color: "White",
price: 10000
},
{
vin: "ddeb9b10",
brand: "Mercedes",
year: 1985,
color: "Green",
price: 25000
}
];
// this.cdRef.detectChanges();
}
The bottom line is this.cdRef.detectChanges(); need to be used carefully and smartly in anywhere in the application if you are using it.
updated stackblitz
Updated Stackblitz: https://stackblitz.com/edit/primeng-p-table-multisort
It worked with overriding the PrimeNG Table - sortMultiple method via prototype chain.
Old code:
Table.prototype.sortMultiple = function () {
var _this = this;
if (this.multiSortMeta) {
if (this.lazy) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
else if (this.value) {
if (this.customSort) {
this.sortFunction.emit({
data: this.value,
mode: this.sortMode,
multiSortMeta: this.multiSortMeta
});
}
else {
this.value.sort(function (data1, data2) {
return _this.multisortField(data1, data2, _this.multiSortMeta, 0);
});
}
if (this.hasFilter()) {
this._filter();
}
}
this.onSort.emit({
multisortmeta: this.multiSortMeta
});
this.tableService.onSort(this.multiSortMeta);
}
};
New code:
Table.prototype.sortMultiple = function () {
const _this = this;
if (this.multiSortMeta) {
if (this.lazy) {
// additional conditions added
if (this.lazyLoadOnInit || (!this.lazyLoadOnInit && this.initialized)) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
} else if (this.value) {
if (this.customSort) {
this.sortFunction.emit({
data: this.value,
mode: this.sortMode,
multiSortMeta: this.multiSortMeta
});
} else {
this.value.sort(function (data1, data2) {
return _this.multisortField(data1, data2, _this.multiSortMeta, 0);
});
}
if (this.hasFilter()) {
this._filter();
}
}
this.onSort.emit({
multisortmeta: this.multiSortMeta
});
this.tableService.onSort(this.multiSortMeta);
}
};

At the same time, two identical elements can not be selected in dropDownList

Hello i am have two kendo ui drodDownList:
kendo-drop-down-list(
ng-model = 'vm.firstList'
k-data-source='vm.filterData'
k-data-text-field='"title"'
k-data-value-field='"name"'
k-value-primitive='true'
k-filter='"contains"'
k-on-change='vm.onChange($event)'
)
and
kendo-drop-down-list(
ng-model = 'vm.secondList'
k-data-source='vm.filterData'
k-data-text-field='"title"'
k-data-value-field='"name"'
k-value-primitive='true'
k-filter='"contains"'
k-on-change='vm.onChange($event)'
)
it is data source:
this.filterData = [
{ name: 'Brown', title: 'Soier' },
{ name: 'Maks', title: 'Inkl' },
{ name: 'Lint', title: 'Baks' },
{ name: 'Hover', title: 'Niyou' }
]
they have same data source, and i am want when choosing item in first dd then remove this item from other dd (and likewise for the second). At the same time, two identical elements can not be selected.
my solution:
in first dd add:
k-on-change='vm.onFirstSelect(kendoEvent)'
k-data-source='vm.firstFilterElements'
for second dd:
k-on-change='vm.onSecondSelect(kendoEvent)'
k-data-source='vm.secondFilterElements'
in controller add:
this.filterElements = [
{ name: 'Brown', title: 'Soier' },
{ name: 'Maks', title: 'Inkl' },
{ name: 'Lint', title: 'Baks' },
{ name: 'Hover', title: 'Niyou' }
]
this.firstFilterElements = this.filterElements;
this.secondFilterElements = this.filterElements;
onFirstSelect(e) {
this.secondFilterElements = this.filterByItem(e);
}
onSecondSelect(e) {
this.firstFilterElements = this.filterByItem(e);
}
filterByItem (e) {
return this.filterElements.filter(function (el) {
return el.name !== e.sender.dataItem(e.item)
[e.sender.options.dataValueField];
});
}
if someone can optimize it i will be glad)

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.

Add a checkbox column in Handsontable

Have you ever make a checkbox column in Handsontable?
I try to use every way to do it, but it's not working.
When user click checkbox on header, all row in column was be checked.
Thanks for any help.
You can create a checkbox column by simply setting the column type option to 'checkbox'.
var $container = $("#example1");
$container.handsontable({
data: data,
startRows: 5,
colHeaders: true,
minSpareRows: 1,
columns: [
{data: "id", type: 'text'},
//'text' is default, you don't actually have to declare it
{data: "isActive", type: 'checkbox'},
{data: "date", type: 'date'},
{data: "color",
type: 'autocomplete',
source: ["yellow", "red", "orange", "green", "blue", "gray", "black", "white"]
}
]
});
For more detail see this example
HTML:
<div id="example2" class="handsontable"></div>
Javascript:
var myData = [{
name: "Marcin",
active: true
}, {
name: "Jude",
active: false
}, {
name: "Zylbert",
active: false
}, {
name: "Henry",
active: false
}]
var $container = $("#example2");
$container.handsontable({
data: myData,
rowHeaders: true,
columns: [{
data: 'name'
}, {
type: 'checkbox',
data: 'active'
}],
colHeaders: function (col) {
switch (col) {
case 0:
return "<b>Bold</b> and <em>Beautiful</em>";
case 1:
var txt = "<input type='checkbox' class='checker' ";
txt += isChecked() ? 'checked="checked"' : '';
txt += "> Select all";
return txt;
}
}
});
$container.on('mouseup', 'input.checker', function (event) {
var current = !$('input.checker').is(':checked'); //returns boolean
for (var i = 0, ilen = myData.length; i < ilen; i++) {
myData[i].active = current;
}
$container.handsontable('render');
});
function isChecked() {
for (var i = 0, ilen = myData.length; i < ilen; i++) {
if (!myData[i].active) {
return false;
}
}
return true;
}
Here's the example you're looking for
http://jsfiddle.net/yr2up2w5/
Hope this helps you.
There's now a checkbox tutorial in the Handsontable documentation.

Resources