How do I skip default sorting in ng-repeat? - angularjs

I am displaying data I get from a json but ng-repeat display it in asc order I want to just display as it is in the json and skip sorting.
Here is my html:
div ng-repeat="(key, data) in List">
<div class="component-title">{{key}}</div>
<div ng-repeat="(key, value) in data">
<div ng-repeat="(key, item) in value">
<div class="row test-label" ng-if="key === 'name'">
<div class="pull-left">
<span class="glyphicon glyphicon-ban-circle"></span>
{{item}}
</div>
<div class="pull-right">
<ul class="pull-right nav nav-pills">
<li><span class="glyphicon glyphicon-pencil"></span></li>
<li>|</li>
<li><span class="glyphicon glyphicon-ban-circle"></span></li>
</ul>
</div>
</div>
</div>
</div>
</div>
My .js file:
(function () {
'use strict';
angular.module('main')
.directive('chTest', function () {
return {
templateUrl: '/templates/chTestDirective.html',
controller: ['$scope', function ($scope) {
$scope.List = {
n: [
{
is_enabled: false,
status: '',
id: 'set',
name: 'set',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list_of_tests',
name: 'list_of_tests',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'single_test',
name: 'single_test',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'all_tests',
name: 'all_tests',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'specific_regex',
name: 'specific_regex',
result: ''
}
],
c: [
{
is_enabled: false,
status: 'running',
id: 'boot-runcommand-delete',
name: 'bootruncommanddelete',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'boot_runcommand_delete_custom_image',
name: 'boot_runcommand_delete_custom_image',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'boot-runcommand-delete-with-disk',
name: 'bootruncommanddeletewithdisk',
result: ''
}
],
ce: [
{
is_enabled: false,
status: '',
id: 'create_delete_node_group_templates',
name: 'create_delete_node_group_templates',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'create_scale_delete_cluster',
name: 'create_scale_delete_cluster',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'create_and_delete_cluster',
name: 'create_and_delete_cluster',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create_and_list_node_group_templates',
name: 'create_and_list_node_group_templates',
result: ''
}
],
k: [
{
is_enabled: false,
status: 'passed',
id: 'boot',
name: 'boot',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list-servers',
name: 'listservers',
result: ''
}
],
neutron: [
{
is_enabled: false,
status: 'running',
id: 'create-and-delete-node',
name: 'createanddeletenode',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create-and-list-node',
name: 'createandlistnode',
result: ''
}
],
g: [
{
is_enabled: false,
status: 'running',
id: 'create-and-delete-image',
name: 'createanddeleteimage',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'create-and-list-image',
name: 'createandlistimage',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'create-image-and-boot-instances',
name: 'createimageandbootinstances',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'list_images',
name: 'list_images',
result: ''
}
],
s: [
{
is_enabled: false,
status: 'passed',
id: 'keystone',
name: 'keystone',
result: ''
},
{
is_enabled: false,
status: '',
id: 'token_validate_cinder',
name: 'token_validate_cinder',
result: ''
},
{
is_enabled: false,
status: '',
id: 'token_validate_neutron',
name: 'token_validate_neutron',
result: ''
},
{
is_enabled: false,
status: 'failed',
id: 'token_validate_heat',
name: 'token_validate_heat',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'token_validate_glance',
name: 'token_validate_glance',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'token_validate_nova',
name: 'token_validate_nova',
result: ''
}
],
q: [
{
is_enabled: false,
status: 'failed',
id: 'nova-update-and-delete',
name: 'novaupdateanddelete',
result: ''
},
{
is_enabled: false,
status: 'running',
id: 'nova-update',
name: 'novaupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'neutron-update',
name: 'neutronupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'cinder-update',
name: 'cinderupdate',
result: ''
},
{
is_enabled: false,
status: 'passed',
id: 'cinder-update-and-delete',
name: 'cinderupdateanddelete',
result: ''
}
]
};
}]
};
});
})();
How can be this achieved? Thanks

In short: Upgrade to 1.4
https://docs.angularjs.org/api/ng/directive/ngRepeat
You need to be aware that the JavaScript specification does not define
the order of keys returned for an object. (To mitigate this in Angular
1.3 the ngRepeat directive used to sort the keys alphabetically.)
Version 1.4 removed the alphabetic sorting. We now rely on the order
returned by the browser when running for key in myObj. It seems that
browsers generally follow the strategy of providing keys in the order
in which they were defined, although there are exceptions when keys
are deleted and reinstated. See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
If this is not desired, the recommended workaround is to convert your
object into an array that is sorted into the order that you prefer
before providing it to ngRepeat. You could do this with a filter such
as toArrayFilter or implement a $watch on the object yourself.

Related

Typescript Angular how to map an object of classes to a single entity

I have an array called panels.
It is setup like this
panels = [
{
active: true,
name: 'Company Information',
disabled: false,
tempControls:[]
},
{
active: true,
disabled: false,
name: 'Locations',
tempControls: []
},
{
active: true,
disabled: false,
name: 'Job Information',
tempControls:[]
}
];
I also have an object of objects that is setup like this
export class AssessmentModel{
companyInformationModel? : CompanyInformationModel;
locationInformationModels? :LocationInformationModel[];
jobInformationModel? : JobInformationModel
}
export class CompanyInformationModel{
companyName?:string = '';
contactName?:string = '';
primaryPhone?:string = '';
secondaryPhone?:string = '';
email?:string = '';
hourlyRate? : string = ''
}
I need to map each object to that in the tempControls with the key of 'Name' and 'Value'
so the panels will look like this with tempControls initialized
panels = [
{
active: true,
name: 'Company Information',
disabled: false,
tempControls:[
'Title': '',
'Value': ''
]
}
]
panels = [
{
active: true,
name: 'Company Information',
disabled: false,
tempControls:[
{
'Title': assessmentModel.CompanyInformationModel."Nameofthefield" (example companyname is the first field inthe class"
'Value': assessmentModel.CompanyInformationModel.companyName
},
{
'Title': assessmentModel.CompanyInformationModel."Nameofthefield" (example contactname is the second field in the class"
'Value': assessmentModel.CompanyInformationModel.contactName
}
]},
{
active: true,
name: 'Job Information',
disabled: false,
tempControls:[
{
'Title': assessmentModel.JobInformationModel."Nameofthefield"
'Value': assessmentModel.JobInformationModel.JobTitle
}
]},
{
active: true,
name: 'Location Information',
disabled: false,
tempControls:[
{ 'Title': assessmentModel.LocationInformationModel[0]."Nameofthefield"
'Value': assessmentModel.LocationInformationModel[0].address1
},
{
'Title': assessmentModel.LocationInformationModel[0]."Nameofthefield"
'Value': assessmentModel.LocationInformationModel[0].address2
}]
,
[
{
'Title': assessmentModel.LocationInformationModel[1]."Nameofthefield"
'Value': assessmentModel.LocationInformationModel[1].address1
},
{
'Title': assessmentModel.LocationInformationModel[1]."Nameofthefield"
'Value': assessmentModel.LocationInformationModel[1].address2
}
]
}
So far I have (but of course this doesn't work)
ngOnInit(){
let model = _assesmentModel;
this.setPanels(model);
}
setPanels(model: AssessmentModel){
this.panels.map(x => x.tempControls.map( y => y.Name = model.companyInformationModel.keys())
}

Return objects from a map function if true

I want to return object(s) from a map function only if documents are checked. Here is the structure of my state.
{
type: ListOfTypes[Math.floor(Math.random() * ListOfTypes.length)],
name: ListOfNames[Math.floor(Math.random() * ListOfNames.length)],
id: nanoid(),
channels: [
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },],
},
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
],
},
{
id: nanoid(),
Name: ListOfChannels[Math.floor(Math.random() * ListOfChannels.length)],
Files: [
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
{ folder: "Folder", id: nanoid(), documents: [{ doc: "WordDoc1.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc2.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc3.doc", isChecked: false, id: nanoid() }, { doc: "WordDoc4.doc", isChecked: false, id: nanoid() }] },
],
}
]
}
I tried to map through the state array but I got an object with un necessary arrays using this.
const handleMoveAll = () => {
const CheckedDocuments = List.map( (connection: any) => (connection.id == connectionId) &&
connection.channels.map( (channel: any) => (channel.id == channelId) &&
channel.Files.map( (file: any) =>
file.documents.map( (doc: any) => doc.isChecked &&
doc
))
)
)
console.log(CheckedDocuments)
}
Is there a better way to loop through the Files array checking for checked documents and returning them in a single array?
Thanks to #HagaiHarari & #oakar.
const handleMoveAll = () => {
const CheckedDocuments = List.flatMap((connection: any) => (connection.id == connectionId) ?
connection.channels.flatMap((channel: any) => (channel.id == channelId) ?
channel.Files.flatMap( (file: any) =>
file.documents.filter( (doc: any) => { if(doc.isChecked) return doc }
))
: []
)
: []
)
console.log(CheckedDocuments)
}

Why ngFor with filter pipe cause infinite loop?

i have this situation.
CheckboxesComponent
<section
*ngFor="let group of model.groups | myfilter:term; let index = index">
<div>
<mat-checkbox
[checked]="group.allChecked"
[ngModel]="group.allChecked"
color="primary">
{{ group.name }}
</mat-checkbox>
</div>
<div>
<ul>
<li *ngFor="let checkbox of groups.checkboxes;">
<mat-checkbox
[checked]="checkbox.check"
[(ngModel)]="checkbox.check"
color="primary">
{{ checkbox.displayName }}
</mat-checkbox>
</li>
</ul>
</div>
</section>
In a second component i have
<mat-form-field
appearance="outline">
<mat-label>
Search by
</mat-label>
<input
matInput
type="text"
[(ngModel)]="filter">
<mat-icon matPrefix fontIcon="icon-search"></mat-icon>
</mat-form-field>
<app-checkbox-group
[datasource]="claims"
[term]="filter"
>
</app-checkbox>
and this pipe
#Pipe({
name: 'roleFilter',
pure: false
})
export class myfilter implements PipeTransform {
transform(groups: [], term: string): [] {
if (!term) {
return groups;
}
return groups
.map(obj => {
return Object.assign({}, obj, {
checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term))
})
})
.filter(obj => obj.checkboxes.length > 0)
}
}
and groups is a dataset like this
[
{
name: 'Group 1',
allChecked: false,
isIndeterminate: false,
checkboxes: [
{
check: true,
displayName: 'first',
name: 'first',
id: '1',
isMandatory: false
},
{
check: false,
displayName: 'second',
name: 'second',
id: '2',
isMandatory: false
},
{
check: false,
displayName: 'third',
name: 'third',
id: '3',
isMandatory: false
},
{
check: false,
displayName: 'fourth',
name: 'fourth',
id: '4',
isMandatory: false
},
{
check: false,
displayName: 'fifth',
name: 'fifth',
id: '5',
isMandatory: false
},
{
check: false,
displayName: 'sixth',
name: 'sixth',
id: '6',
isMandatory: false
},
{
check: false,
displayName: 'seventh',
name: 'seventh',
id: '7',
isMandatory: false
},
{
check: false,
displayName: 'eighth',
name: 'eighth',
id: '8',
isMandatory: false
},
]
}
]
When i start typing on the input filter, to reduce the dataset, if i start typing with a letter that not match with any displayName all groups are hidden and it's work like expected.
The problem appears when i start typing with a letter that match with some of the displayName property of the checkboxes.
I don't understand why but all page freeze and the map function is called infinite times.
The problem seem to be in
Object.assign in the map method. Because if i change this line with
obj.checkboxes = checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term)) it works but replace the original checkboxes with the filtered one.
In accordion to #Andrei comment
try to add trackByIndex(idx) {return idx;} method and pass it to both ngFor insatnces like this *ngFor="let checkbox of groups.checkboxes; trackBy: trackByIndex"
The solution was using the trackBy pipe on both *ngFor directives.

Looping nested array Object in ListView React native

I currently trying to play around with react-native..
I want to make a list view that get the dataSource from var which contain an object that have nested array inside.
var questionArray = [
{
question: "What is the emotion of the user? choose all that apply!",
answerArray: [
{ name: "Cheerful", status: true, answered: false },
{ name: "Impulsive", status: false, answered: false },
{ name: "Firm", status: false, answered: false },
{ name: "Merry", status: true, answered: false },
{ name: "Jumpy", status: false, answered: false },
{ name: "Energetic", status: false, answered: false },
{ name: "Glowing", status: false, answered: false },
{ name: "Animated", status: false, answered: false },
{ name: "Lively", status: false, answered: false },
{ name: "Creepy", status: false, answered: false },
{ name: "Excited", status: true, answered: false },
{ name: "Tense", status: false, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Pleased", status: true, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Hasty", status: false, answered: false },
{ name: "Delighted", status: true, answered: false },
{ name: "Hedonistic", status: false, answered: false },
{ name: "Eager", status: false, answered: false },
{ name: "Joyful", status: false, answered: false },
]
},
{
question: "What is the best way to describe this person's character? Choose all that apply.",
answerArray: [
{ name: "Cheerful", status: true, answered: false },
{ name: "Impulsive", status: false, answered: false },
{ name: "Firm", status: false, answered: false },
{ name: "Merry", status: true, answered: false },
{ name: "Jumpy", status: false, answered: false },
{ name: "Energetic", status: false, answered: false },
{ name: "Glowing", status: false, answered: false },
{ name: "Animated", status: false, answered: false },
{ name: "Lively", status: false, answered: false },
{ name: "Creepy", status: false, answered: false },
{ name: "Excited", status: true, answered: false },
{ name: "Tense", status: false, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Pleased", status: true, answered: false },
{ name: "Unrestful", status: false, answered: false },
{ name: "Hasty", status: false, answered: false },
{ name: "Delighted", status: true, answered: false },
{ name: "Hedonistic", status: false, answered: false },
{ name: "Eager", status: false, answered: false },
{ name: "Joyful", status: false, answered: false },
]
}
];
and I called this variable inside render ListView which trigger renderRow function..
_renderRow( rowData, sectionID, rowID ) {
return (
<View>
<Text>{rowData.question}</Text>
<Text>{rowData.answerArray[0].name}</Text>
</View>
);
}
render() {
return (
<View>
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
/>
</View>
);
}
How do I render the loop inside this listView ?
Even the when I hard coded the index like above code, it's not working..
Thank you.
You should make two separate Components: Question & Answer
I've made a Codepen for you as an example, using your data
At first, I pass the questionsArray as prop to the ListView Component:
class Application extends React.Component {
render() {
return (
<div>
{ questionsArray.map((question, key) => <ListView key={`listview-${key}`} question={question} />) }
</div>
);
}
}
Then, you can pass the answers to the ListViewItem Component, like this:
class ListView extends React.Component {
render() {
return (
<div>
{this.props.question.question}
{this.props.question.answerArray.map((answer, key) => <ListViewItem answer={answer} />)}
</div>
);
}
}
This is the ListViewItem:
class ListViewItem extends React.Component {
render() {
return (
<div>
{this.props.answer.name}
</div>
);
}
}

AngularJS filter by dropdown value

I have a problem with filter my data by category selected by dropdownlist.
Here how looks like my controller:
var category = {
"Dairy": 1,
"Bread": 2,
"Drink": 3,
"Spices": 4,
"Meat": 5
}
$scope.categories = [
{ text: "All", value: 0 },
{ text: "Dairy", value: 1 },
{ text: "Bread", value: 2 },
{ text: "Drink", value: 3 },
{ text: "Spices", value: 4 },
{ text: "Meat", value: 5 }
];
$scope.products = [
{ name: "Milk", value: 3.28, avaible: true, expireDate: "2016-04-29", category: category.Dairy },
{ name: "Serek wiejski", value: 1.28, avaible: false, expireDate: "2016-04-26", category: category.Dairy },
{ name: "Coca-cola", value: 6.98, avaible: true, expireDate: "2017-04-29", category: category.Drink },
{ name: "Corn", value: 0.99, avaible: true, expireDate: "2016-09-19", category: category.Spices },
{ name: "Ham", value: 9.00, avaible: true, expireDate: "2016-04-29", category: category.Meat },
{ name: "Bread", value: 3.78, avaible: true, expireDate: "2016-04-29", category: category.Dairy }
];
Here is HTML
<select ng-model="selectedCategory">
<option ng-repeat="cat in categories" value="{{cat.value}}">
{{cat.text}}
</option>
</select>
<div ng-repeat="product in products | filter: product.category == selectedCategory">
After I change value of dropdown the products are not being filtered. Just for id = 5 it works as expected.
Is condition product.category = selectedCategory wrong?
try this
<div ng-repeat="product in products | filter:{category:selectedCategory}">

Resources