Render last element of nested array of Object in Angular HTML template - arrays

I have an Object named comment, which has description property and editedDescription Array. Whenever user edits description, new description will be pushed into editedDescription array.This array is used so as to maintain history of edited descriptions.
Following is my comment Object :
export interface Comment {
userName: String,
userImage: String,
description: String,
upvote : Number,
downvote : Number,
createdDate: Date,
replies: [
{
userName: String,
userImage: String,
description: String,
upvote : Number,
downvote : Number,
createdDate: Date
}
],
editedDescription: [
{
Description: String,
editedDate: Date
}
]
}
In order to output last element of editedDescription array, I have tried :
{{ comment?.editedDescription[editedDescription?.length-1]?.Description}}
I am getting following error - 'Cannot read property '-1' of undefined '
I have made use of safe navigation operator to check if array exists but im getting cannot read -1 of undefined
this is my code where in part is failing
<div *ngIf="comment?.editedDescription?.length == 0 ; else edited_comment">
<p> {{ comment?.description }}</p>
</div>
<ng-template #edited_comment>
<p> {{ comment?.editedDescription[editedDescription?.length-1]?.Description}}</p>
</ng-template>
*ngIf conditions check if there is no data in editedDescription array, use description property else use last element of editedDescription array.

I think it needs to be the following, as at the moment you are not trying to access the array through comment where it sounds like it is stored.
{{ comment?.editedDescription[comment.editedDescription.length -1 ]?.Description}}
You still need to access comment when looking for the length. Put the safety operators back in when you are happy it is working. Below shows a simplified example of what you have tried.
const obj = { hello: [1, 2, 3] };
console.log(obj.hello[obj.hello.length - 1]); // last element, expected 3
// console.log(obj.hello[hello.length - 1]) // This is like what you have done.

Related

Reactjs # symbol in parameter: item.enclosure.#attributes how to fix, that this is possible?

I have a .map function in my code and Im getting data from a json output but one of the item parameters is: #attribute but I cant have an # symbol in the parameter so is there any way I can fix this?
I coudn't really find anything about this because I'm not sure what to search for except for # symbol in parameter.
this is the code I used to get the data:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure.#attributes)
{#attributes: {…}}
#attributes:
length: "0"
type: "image/jpeg"
url: "https://media.nu.nl/m/aoqxps0aijuy_sqr256.jpg/barnier-eu-niet-onder-de-indruk-van-no-deal-brexit-dreigement.jpg"
__proto__: Object
__proto__: Object
So how can I fix that I can have an # in the parameter and it properly gets the data from the json.
Try this:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure["#attributes"])
});
Retrieving the value of a property
We can retrieve the value of a property using 2 different syntaxes.
const car = {
brand: {
name: 'Ford'
},
color: 'blue',
'the color': 'blue'
}
The first is dot notation:
car.color
The second, which is mandatory for properties with invalid names, is to use square brackets:
car['the color']
or even mixing:
car.brand['name']
car['brand'].name

Unable to display values from dynamic array, ionic 2

I have defined array like this
addressData: Array<
{
title: any, city: any,country: any,
locality1: any,locality2: any,state: any,
street:any, zip_code:any,icon: any,
showDetails: boolean
}> = [];
Now i push the values of array like this
this.addressData.push
({
title: 'Address',
city:this.mapDetails.address[0].city,
country:this.mapDetails.address[0].country,
locality1:this.mapDetails.address[0].locality1,
locality2:this.mapDetails.address[0].locality2,
state:this.mapDetails.address[0].state,
street:this.mapDetails.address[0].street,
zip_code:this.mapDetails.address[0].zip_code,
icon: 'ios-add-circle-outline',
showDetails: false
});
mapDetails - contains array object , with object name as address and which is at index 0, hence i am using "this.mapDetails.address[0]" to access values.
In HTML i am using ngFOr to iterate values like this
<ion-item padding *ngFor="let d of addressData" (click)="toggleDetails(d)"><ion-icon color="primary" item-right [name]="d.icon"></ion-icon>
{{d.title}}
<div *ngIf="d.showDetails">
{{d.street}}<br/>
{{d.locality2}}<br/>
{{d.city}} - {{d.zip_code}}<br/>
{{d.state}} - {{d.country}}<br/>
</div>
</ion-item>
The issue is, the error which I am getting is
"ModalCmp ionViewPreLoad error: Cannot read property 'address' of undefined"
Help me out with this error please.

mongoose query: find an object by id in an array

How could I find an image by id in this Schema. I have the id of the User and the id of the image I am looking for. What would be the best way to do this and do all images in this case have different ids or could they have the same id because they don't belong to the same User?
My Schema looks like this:
var userSchema = new Schema({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
name: String,
about: String,
images: [{
id: Schema.ObjectId,
link: String,
main: Boolean
}]
});
When you are interested in the full object it is a simple find:
.find({"facebook.id":"<id>", "images.id":<image-id>})
I don't think that there is a way to reduce the image array in the result.
To update a single element in the image array you can use this:
.update({"facebook.id":"<id>", "images.id":<image-id>}, {$set : {"images.$.main" :false} } );
userSchema .find({facebook.id: "some ID",{ "images.id": { $in: [ id1, id2, ...idn] }}
since images are inside the document you can have same ID's however every time you query you should keep in mind that you send some other parameters such as facebook.id or facebook.email along with image id's to retrieve them. Otherwise you end up getting all that might be irrelevant only because you decide to keep same ID's for images.
tl;dr
I struggled with this and came up with a solution. Like you, I was trying to query for a deeply nested object by the _id, but I kept coming up empty with the results. It wasn't until I did some type checking that I realized the id value I was getting from my frontend, while directly supplied by mongoose, was in fact a String and not an Object.
I realize this question was already partially answered before, but that person's solution didn't work for me, and the comment on the answer tells me you wanted to update the specific image you queried for, which is exactly what I was trying to do.
The solution
In order to select an object from the nested array by the _id value, first you'll have to install the npm package bson-objectid and use the provided method to convert your string into an objectId in your query.
In your terminal:
npm i bson-objectid
In your code:
const ObjectId = require('bson-objectid')
userSchema.findOneAndUpdate(
{ "facebook.id": <user-id>, "images._id": ObjectId(<image-id>) },
{ "$set": { "images.$.main": false } },
{ new: true }, // an extra options parameter that returns the mutated document
(err, user) => {
if (err) {
handleErr(err)
} else {
console.log(user)
// do something with new user info
}
)

Convert an iterable map object to array object in ReactJS

I'm trying to load some json file in a DropdownList from react-widgets. When I load the json file the data type looks like this:
Map {size: 1, _root: ArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
__altered
:
false
__hash
:
undefined
__ownerID
:
undefined
_root
:
ArrayMapNode
size
:
1
__proto__
:
KeyedIterable
While the Dropdown component (from react-widgets) needs an array! So It makes this error:
Failed propType: Invalid prop `data` of type `object` supplied to `DropdownList`,
expected `array`. Check the render method of `Uncontrolled(DropdownList)`.
I can't load the json file directly and I have to use ajax to load it (or technically I can but it's a huge file and each time the user click on the dropdown list it takes couple of seconds to load the data from file). How can I convert this to an array?
P.S. The json file looks like this:
{
"items":[
{
"id": "aaa",
"name": "english"
},
{
"id": "aab",
"name": "Swedish"
},
]
}
I think you're looking for something along the lines of:
var dropdownList = jsonObject.items.map((item, i) => {
return (
<option key={i} val={item.id}>{item.name}</option>
);
})
The Array.prototype.map function simply goes over a list and produces a new list of the same size but with changes based on the modifier/callback function.
Update based on comment:
Based on the docs for DropdownList, you have two options for passing data to the list: a flat array of item names, or a list of objects with specific keys for the item name and value.
Option 1: flat list of item names
var itemNames = jsonObject.items.map((item) => item.name );
Option 2 : list of objects
var items = jsonObject.items.map((item) => {
return {
textField: item.name,
valueField: item.id
}
});
The benefit to using the second option would be when someone selects one of the items, the event that is created with point to the val attribute of the HTML <option>. This is useful for you especially since your ids and names are not the same. An example:
Option 1 (from above):
<DropwdownList
data={itemNames}
onSelect: (event) => {
// Will give the `val` attribute set by DropdownList
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>
Option 2 (from above):
<DropwdownList
data={items}
onSelect: (event) => {
// Will give the `valueField` attribute you set, which for you is the item's `id` field
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>

In AngularJS, is it possible to filter inside of a specific element of an array using only a view?

I've got some data like this:
people = [
{
names: [
{first: "Joe", last: "Smith"},
{first: "Joseph", last: "Smith"},
...
]
},
...
]
In other words, an array of objects with an array of names. For example, a person could be called "Joe Smith" or "Joseph Smith". How can I use a filter to only search the first element of names? IE: If I typed in "Jo" or "Smith" it would find the first person. But, if I typed in "seph" it wouldn't.
I've been looking at the examples on this page, but there isn't really an example of filtering inside arrays. Here's what I've tried but it gives me an error:
<input ng-model="search.names[0].$">
TypeError: Cannot set property '$' of undefined
Working Code
Input HTML
<input ng-model="searchTerm">
Results
<tr ng-repeat="p in people | filter:searchFunc">...</tr>
Controller
$scope.searchFunc = function(person) {
var firstPersonsName = [person.names[0]]; // Wrapping in array since the 'filter' $filter expects an array
var matches = $filter('filter')(firstPersonsName, $scope.searchTerm); // Running firstPersonsName through filter searching for $scope.searchTerm
return matches.length > 0;
}
Plunker Demo
Answer to the question in your title
I played around with filter and it doesn't seem like you can go beyond one level deep when specifying a pattern object for it e.g. ng-model="search.names" works but ng-model="search.names.otherVal" doesn't.
Also, even if filter supported going beyond one level deep, you still wouldn't be able to do ng-model="search.names[0]". This is because filter expects the input to be an array, but the elements of your names array are all objects e.g. people[0].names[0] == {first: "Joe", last: "Smith"} so filtering will never work.
The only way to do what you are asking purely through the view and no extra code in your controller is to just create your own custom filter that handles your case.
Would this do the trick?
Say that your input is
<input ng-model="search.name" type="text">
Then, you can display results like this:
<div ng-repeat="person in people[0].names | filter: alias">...</div>
Controller:
$scope.alias = function (object) {
if (object.first.match(new RegExp($scope.search.name))) {
return true;
}
return false;
};

Resources