PrimeNG cascading dropdowns: initialize child dropdown - dropdown

How do I initialize the child dropdown based on the value of the parent dropdown?
app.component.html
<p-dropdown [options]="states" [(ngModel)]="selectedState" (onChange)="getCities($event.value)"></p-dropdown>
<p-dropdown [options]="cities"></p-dropdown>
app.component.ts
export class AppComponent implements OnInit {
cities: SelectItem[];
selectedState: string;
stateNames = ['Alabama', 'Alaska', 'California'];
states = this.stateNames.map((val, i, stateNames) => {
return { label: val, value: val }
});
cityNames = [
{state: 'Alabama', city: 'Birmingham'},
{state: 'Alabama', city: 'Huntsville'},
{state: 'Alabama', city: 'Montgomery'},
{state: 'Alaska', city: 'Anchorage'},
{state: 'Alaska', city: 'Juneau'},
{state: 'California', city: 'Fresno'},
{state: 'California', city: 'Perris'}
];
ngOnInit() {
this.getCities(this.selectedState);
}
getCities(state):any[] {
this.cities = this.cityNames
.filter((el) => { return el.state === state })
.map((el) => { return { label: el.city, value: el.city } });
}
}
Plunker example

You have to initialize selectedState with the first country from stateNames in ngOnInit :
this.selectedState = this.stateNames[0];
See Plunker

Related

Angular Custom Pipe - Multilevel Filtering

I have a set of data which I need to filter via pipe. Now, in that data array, some objects have a nested array. Similar to this:
this.testArray = [
{
name: "Ford",
cars: [
{
name: "Figo",
year: "2015"
},
{
name: "Ecosport",
year: "2021"
},
{
name: "Endeavour",
year: "2021"
}
],
location: "USA"
},
{
name: "Suzuki",
location: "Japan"
},
{
name: "Honda",
cars: [
{
name: "Brio",
year: "2015"
},
{
name: "Amaze",
year: "2021"
},
{
name: "CR-V",
year: "2021"
}
],
location: "Japan"
},
{
name: "Hyundai",
cars: [
{
name: "Tucson",
year: "2015"
},
{
name: "Creta",
year: "2021"
},
{
name: "Venuw",
year: "2021"
}
],
location: "South Korea"
},
{
name: "Renault",
cars: [
{
name: "Duster",
year: "2015"
},
{
name: "Scala",
year: "2021"
},
{
name: "Kwid",
year: "2021"
}
],
location: "France"
}
];
Now, the requirement is that when I type a company name it should filter and when I type a car name, the same should happen with the nested array returning only the filtered car name. Eg: If I search for 'Figo', it should return me Ford and then Figo nested inside.
here is my pipe I am using for this:
#Pipe({ name: "carCompSearch" })
export class CarCompSearch implements PipeTransform {
transform(carData: [], searchString: string) {
if (!carData || !searchString) {
return carData;
}
return carData.filter((item: any) => {
return item.name.toLowerCase().includes(searchString.toLowerCase());
});
}
}
I know the pipe is incomplete. Need help in completing this.
and here is the template:
<div *ngFor="let comp of testArray | carCompSearch: searchString">
<h2>{{comp.name}}</h2>
<h5>{{comp.location}}</h5>
<ul>
<li *ngFor="let model of comp.cars">
<span>{{model.name}} - {{model.year}}</span>
</li>
</ul>
</div>
your help is appreciated.
Here is the fork link:
https://codesandbox.io/s/custompipe-forked-5urrl
This may help you out:
#Pipe({ name: "carCompSearch" })
export class CarCompSearch implements PipeTransform {
transform(carData: any[], searchString: string) {
if (!carData || !searchString) {
return carData;
}
const carDataWithNestedFilter = carData.map((item) => {
const newItem = { ...item }; // copy the item to not manipulate the original one
newItem.cars = item.cars?.filter((car) =>
car.name.toLowerCase().includes(searchString.toLowerCase())
);
return newItem;
});
return carDataWithNestedFilter.filter((item) => {
const nameIncludes = item.name
.toLowerCase()
.includes(searchString.toLowerCase());
return item.cars?.length > 0 || nameIncludes;
});
}
}

How to prevent lodash map from creating a nested object?

I want to map an array of objects and add a property to each item. At the moment the original values get nested. How can I change it to get an item with a flattened object?
code example
import _ from 'lodash';
let arr = [{name: "tim"}, {name: "tom"}]
const id = {id: 1}
console.dir(_.map(arr, item => ({...id, item})));
result:
[ { id: 1, item: { name: 'tim' } },
{ id: 1, item: { name: 'tom' } } ]
wished result:
[ { id: 1, name: 'tim' },
{ id: 1, name: 'tom' } ]
Spread the item as well:
let arr = [{name: "tim"}, {name: "tom"}]
const id = {id: 1}
console.dir(_.map(arr, item => ({ ...id, ...item })));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Or use _.merge() with lodash/fp:
const mergeId = id => _.map(_.merge(id))
let arr = [{name: "tim"}, {name: "tom"}]
const id = {id: 1}
result = mergeId(id)(arr)
console.dir(result);
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>

How do I update the state of a array element?

I have an array of below format
constructor(){
super();
this.state = {
details: [
{
id: 1,
class: '10',
section: 'A',
subject: 'Social',
name: 'abc'
},
{
id: 2,
class: '8',
section: 'C',
subject: 'Social',
name: 'abc'
},
{
id: 3,
class: '9',
section: 'A',
subject: 'Social',
name: 'abc'
}
]
}
I want to update each name in a loop. How can I update the state. I am trying with the below code.
this.state.details.map((item, key) => {
this.setState({
details.key.name: 'trial'
})
})
You can do it like this.
modifiedData = this.state.details.map((item, index) => { return { ...item, name: "trial" } })

How to store Array of Objects in realm-js?

import Realm from 'realm';
class Cities extends Realm.Object {}
class Users extends Realm.Object {}
Cities.schema = {
name: 'Cities',
properties: {
'name': {
type: 'string'
},
'pincode': {
type: 'int'
}
}
};
Users.schema = {
name: 'Users',
primaryKey: 'id',
properties: {
'id': 'string',
'name': {
type: 'string'
},
'city': {
type: 'list',
objectType: 'Cities'
}
}
};
const schemaList = [Users, Cities];
const realmInstance = new Realm({schema: schemaList});
export default realmInstance;
// pushing a cityObj (that is already present in 'Cities') for a existing User:
onPress={() => this.addCity({name: 'Delhi', pincode: 110004})}
addCity = (cityObj) => {
realm.write(() => {
let user = realm.create('Users', {
'id': 'someUniqueID'
}, true);
user.city.push(cityObj);
});
let cities = realm.objects('Cities');
console.log('cities.length', cities.length);
}
though, trying to update a record in 'Users', The write transaction is writing a new record in Cities table as well creating duplicates. Why so?
Adding to a list will in general create a new object. But you can add a primary key to Cities, create/update the object first and finally push it to the list. Something like:
const Realm = require('realm');
const CitiesSchema = {
name: 'Cities',
primaryKey: 'pincode',
properties: {
'name': {
type: 'string'
},
'pincode': {
type: 'int'
}
}
};
const UsersSchema = {
name: 'Users',
primaryKey: 'id',
properties: {
'id': 'string',
'name': {
type: 'string'
},
'city': {
type: 'list',
objectType: 'Cities'
}
}
};
const schemaList = [UsersSchema, CitiesSchema];
const realm = new Realm({schema: schemaList});
addCity = (cityObj) => {
realm.write(() => {
let city = realm.create('Cities', cityObj, true);
let user = realm.create('Users', {
id: 'someUniqueID',
name: 'Foo Bar'
}, true);
user.city.push(city);
});
let cities = realm.objects('Cities');
console.log('cities.length', cities.length);
}
addCity({name: 'Delhi', pincode: 110004});
addCity({name: 'Delhi', pincode: 110004});

Angular 2 mocking method and calling

I'm trying to call a mocked service and update the user variable, but when I call the mocked service nothing changes?
I am generally struggling with testing, if there are any good resources to learn with angular2 I'm all ears.
let users = [{ name: 'Test', lastname: 'User' }, { name: 'Test2', lastname: 'User2' }];
let addedUsers = [{ name: 'blah', lastname: 'blah' },{ name: 'Test', lastname: 'User' }, { name: 'Test2', lastname: 'User2' }];
describe('Component: UserList', () => {
beforeEach(() => {
userServiceStub = {
getUsers: () => {
return Observable.of(users);
},
getUser: () => {
return Observable.of(user);
},
addUser: () => {
users.push({ name: 'blah', lastname: 'blah' });
}
};
TestBed.configureTestingModule({
declarations: [UserListComponent],
imports: [HttpModule],
providers: [
{provide: UsersService, useValue: userServiceStub },
{ provide: Router, useClass: RouterStub }
]
});
app = fixture.debugElement.componentInstance;
userService = fixture.debugElement.injector.get(UsersService);
it('should call addUser on button click', () => {
let spy = spyOn(userService, 'addUser');
userService.addUser('argument');
fixture.detectChanges();
expect(users).toEqual(addedUsers);
});
});