How to display value of object sent by node - angularjs

I have question i try to put value from nodejs by init() in angularjs, later i put to $scope.product and when i try display i have problem with:
node:
return res.render('product/product', { title: 'Express', product: products });
angular:
<body ng-controller="productsController" ng-init="productView('<%= product %>')">
<% include ../share/header.ejs %>
{{ product.title }}
{{ product.price }}
</body>
controller:
$scope.productView = function (product) {
$scope.product = JSON.parse(product);
console.log(product);
};
Error: [$parse:syntax] Syntax Error: Token 'bf' is unexpected, expecting [)] at column 55 of the expression [productView('{ _id: 5950c8902a76e81b5cc56a6f, title: 'bf', price: 7, __v: 0 }')] starting at [bf', price: 7, __v: 0 }')].

product: products - it's possible you are passing down an array of objects instead of an individual one. If that's the case, either change the res.render call on the server to pass only 1 product, or change the client-side code to expect an array and use something like ngRepeat to iterate over them.

you dont need productView function, try simply
<body ng-controller="productsController" ng-init="product='<%= product %>'">
{{ product.title }}
{{ product.price }}

Related

Return an array element inside a nested array

I've got one that I'm not getting too much traction on, Ive got everything working correctly except one element. Essentially I want to filter a return of "ev3_4" in the code. I'm not sure of the correct function. I'm pulling from an external source to get the data. and the info is inside a nested array of the array that I have been able to correctly return.
<template>
<!-- the array for the ev data -->
<div id="ev-deck" class="content">
<div id="text-box-ev" class="field">
<div class="control">
<!-- To change the number of events shown change the value for X in v-for="item in infodata.slice(0, X), this is the limiter for how many will loop before it stops -->
<div class="card-content has-background-dark has-text-light" id="ev-card" v-for="item in p3data.slice(0, 2)" :key="item.infodata">
<!-- Every row is a separate line in the event element and its position is manipulated by the column css -->
<div class="row">
<div id="ev-title" class="column"> <b>ev1:</b> {{ item.ev1 (firstname) }}</div>
<div id="ev-title" class="column"><b>ev2:</b> {{ item.ev2 (lastname)}}</div>
<div id="ev-title" class="column"><b>ev3:</b> {{ item.ev3_4 (city)}}</div>
</div>
<div class="row">
<div id="ev-title" class="column"><b>ev4:</b> {{ item.ev4 }}</div>
<div id="ev-title" class="column"><b>ev5:</b> {{ item.ev5 }}</div>
</div>
<div class="row">
<div id="ev-title" class="column-centered"><b>ev6:</b> {{ item.ev6 }}</div>
</div>
<div class="row">
<div id="ev-title" class="column-centered"><b>ev7:</b> {{ item.ev7 }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ev',
}
data() {
return {
infodata: [],
},
// I know this is wrong and need help making this logic correct
item.ev3.filter(data => {
return data.ev3 === item.ev3_4
})
},
created() {
var info = 'some url'
axios.get(info)
.then( response => {
this.infodata = response.data;
console.log(response.data);
})
},
</script>
Here is an example of the the array its pulling
(infodata Array)
0:
ev1 (first name): joe
ev2 (lastname): blow
ev3 (address):
0:
ev3_1 (street number): 1234
ev3_2 (street name): main
ev3_3 (zip code): 12345
ev3_4 (city): tempe
Thanks for updating your question. Glad to hear you found a solution to access the data you needed.
Based on your edit, I think there are still some things worth noting. The data you are referring to is actually stored in an object rather than an array (though it does contain an array).
An array has the structure:
data = ["val1", "val2", "val3"]
And the data is accessed by index.
data[0] -> "val1"
data[1] -> "val2"
data[data.length - 1] -> "val3"
ev3[0]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
Objects, on the other hand, contain properties consisting of key-value pairs. And have the following structure:
data: {
val1: "first",
val2: "second",
val3: {
a: "third a",
b: "third b",
c: "third c"
}
}
Object values are accessed using the key.
data.val1 -> "first"
data.val3.b -> "third b"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
Given the solution that worked for you,
item.ev3[0].ev3_4
Your data is stored as an object (item) with a property (ev3) that contains an array whose first index ([0]) is an object that has a property (ev3_4).
Your edit to your question definitely helps to clarify the structure of your data.
0:
ev1 (first name): joe
ev2 (lastname): blow
ev3 (address):
0:
ev3_1 (street number): 1234
ev3_2 (street name): main
ev3_3 (zip code): 12345
ev3_4 (city): tempe
But there are still some adjustments that you could make that would greatly improve your ability to work with and follow your data. And might help further clarify the concepts.
First, I would highly recommend using clear names for your object keys. What you have included in brackets is perfect, just use camel case to eliminate spaces.
This will make things much easier for you when writing code to accesses data (item.address.city as opposed to using names like ev3 and ev3_4), and will also help make your code more readable for others trying to follow your code.
Second, you are storing your address data (ev3[0]) as an object, inside of an array (hence the [0]).
From what you have shown, you are only using the first index of the array ([0]).
If this is the case you can just store the address object directly inside ev3, which will eliminate the need for you to specify [0] when you access the data.
person: {
firstName: "Joe",
lastName: "Blow",
address: {
streetNumber: "1234"
streetName: "Main Street",
zipCode: "90210",
city: "Fakesville"
},
phone: "1(222)333-4444"
}
Now you are able to access the same data you were looking to with the following:
person.address.city
And if you have additional people to store, that could/should be done inside an array, where they can then be accessed by their index or in a loop.
people = [
{
firstName: "Joe",
lastName: "Blow",
address: {
streetNumber: "1234"
streetName: "Main Street",
zipCode: "90210",
city: "Fakesville"
},
phone: "1(222)333-4444"
},{
firstName: "Rick",
lastName: "Sanchez",
address: {
streetNumber: "132"
streetName: "Cool Avenue",
zipCode: "98101",
city: "Seattle"
},
phone: "1(222)333-4444"
}
]
people[1].address.city -> "Seattle"
people[0].firstName -> "Joe"

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

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.

Two-tier sorting for ng-repeat

For example, I have the following collection used for ng-repeat:
$scope.pokedex = [{
type: "Fire",
pokemon: ["Charizard", "Moltres"]
},{
type: "Rock",
pokemon: []
},{
type: "Fighting",
pokemon: ["Machamp", "Hitmonchan"]
},{
type: "Dragon",
pokemon: []
}];
This collection will be churned out in a ng-repeat directive. In the actual application, the collection will be retrieved from a database, so it may be unsorted. I want to sort it in the following manner: priority sort types with Pokemon to the top, then sort each group by name.
Edit: I need to clarify what the backend data consists of. In the above example, $scope.pokedex consists of a constant number of types - these are categories. The application retrieves Pokemon from the database and fill up each category's list accordingly. The full range of types is intentionally hardcoded into the array and will remain unchanged regardless of whether the list of Pokemon in it is empty or not.
When the web page is generated using ng-repeat, the desired end state is as follows:
An accordion is displayed with each type as a header, and the list of Pokemon in the body as a list/table.
All empty categories shall be disabled but still visible, their headers given a particular CSS format, and all of them PUSHED TO THE BOTTOM beneath the non-empty categories.
The empty group and non-empty group shall individually be sorted by category/type name.
Everything except the pushing of empty groups to the bottom and the sorting by name have been implemented. These are my final requirements to implement.
How can I do that? Is there a way to do it in advance, or via orderBy during ng-repeat, or any other workable solution?
You Can Try like this This
<ul>
<li ng-repeat="people in peoples | orderObjectBy:'pokemon':true">{{ people.name }}</li>
</ul>
Please try the code below
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="pokemonController">
<ul>
<li ng-repeat="people in peoples | orderBy:['-pokemon.length','name']">
name: {{people.name}} - number of Pokemons: {{people.pokemon.length}}
<hr />
</li>
</ul>
</div>
</div>
<script>
var app = angular.module('myApp',[]);
app.controller('pokemonController', ['$scope', function($scope){
$scope.peoples = [{
name: "Obama",
pokemon: ["Charizard", "Dragonite", "Moltres"]
},{
name: "Merkel",
pokemon: []
},{
name: "Putin",
pokemon: ["Machamp", "Hitmonchan"]
},{
name: "Kim",
pokemon: []
}];
}]);
</script>

how do i filter items by property in ng-options?

I have some data and a select control as you can see from my code sample below. It works for me but I want to be able to filter the data by type. In my code sample, I show one way I have tried to filter the data based on the type being a value of one. I am not sure if the way I am creating the select is causing this simple inline filter to not work or if I am doing something wrong?
$scope.data = [{
name : "5 play",
type : 1
}, {
name : "one on one",
type : 2}, {
name : "two on one",
type : 2}];
<select class="form-control" ng-model="selectedRule"
ng-options="item as (item.Name) for item in data track by item.Name | filter:{type:1}"></select>
As stated in angular docs, track by must always be the last expression:
Note: track by must always be the last expression
My guess is that all that follows is not considered, so that´s why your filter wasn´t applying. Moving the track by to the right place should fix it
Yes, as mentioned. Move the track by at the end and make the letter N lowercase like in the following demo or in this fiddle.
angular.module('demoApp', [])
.controller('mainController', MainController);
function MainController($scope) {
$scope.data = [{
name: "5 play",
type: 1
}, {
name: "one on one",
type: 2
}, {
name: "two on one",
type: 2
}];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<select class="form-control" ng-model="selectedRule" ng-options="item as item.name for item in data | filter:{type:1} track by item.name"></select>
</div>

angularJS - How to filter by one item in object only

In this JSFiddle (https://jsfiddle.net/eug0taf9/9/), I select a rating and expect an image to be displayed.
What is happening?
When I select rating 'High', 2 images show up instead of 1 because the filter is catching category 'High' and also description 'High' of an image in category 'Low'.
What do I expect to happen?
On selecting rating "High", I only want the category to be filtered. I don't need it to be filtered by description too.
Any suggestions on how to solve this?
HTML code:
<div ng-app="myApp" ng-controller="myCtrl">
<span>Select a rating</span>
<select ng-model="catselect"
ng-options="category for category in imageCategories"
ng-change="valueSelected(catselect)">
<option value>All</option>
</select>
<!--<p>Select <input ng-model="categories"/></p>-->
<ul class="photosmenu">
<li ng-repeat="image in images | filter : catselect" ng-click="setCurrentImage(image)">
<img ng-src="{{image.image}}" alt="{{image.stars}}" width="300px"/>
</li>
</ul><!-- End of List -->
</div>
Angular Code:
var mod = angular.module("myApp", []);
mod.controller("myCtrl", function($scope){
$scope.images = [
{category: 'High', image: 'img/1.png', description: 'Random Photo', stars: '4/5'},
{category: 'Medium', image: 'img/6.png', description: 'ApplePhoto', stars: '3/5'},
{category: 'Low', image: 'img/13.png', description: 'High Top Photo', stars: '2/5'},
{category: 'None', image: 'img/16.png', description: 'Kilt Photo', stars: '0/5'}];
$scope.currentImage = $scope.images[0];
$scope.imageCategories = ["High", "Medium", "Low", "None"];
$scope.valueSelected = function (value) {
if (value === null) {
$scope.catselect = undefined;
}
};
});
That is because you have a global match filter which will match on all properties, if you want to filter on specific property set your filter object accordingly. i.e
<li ng-repeat="image in images | filter :{category: catselect}"
Demo
or you could also set your ng-model to an object,
<select ng-model="catselect.category"
and do:
<li ng-repeat="image in images | filter :catselect"
Demo
Check out documentation:
string: The string is used for matching against the contents of the array. All strings or objects with string properties in array that match this string will be returned. This also applies to nested object properties. The predicate can be negated by prefixing the string with !.
Object: A pattern object can be used to filter specific properties on objects contained by array. For example {name:"M", phone:"1"} predicate will return an array of items which have property name containing "M" and property phone containing "1". A special property name $ can be used (as in {$:"text"}) to accept a match against any property of the object or its nested object properties. That's equivalent to the simple substring match with a string as described above. The predicate can be negated by prefixing the string with !. For example {name: "!M"} predicate will return an array of items which have property name not containing "M".

Resources