AngularJS - accessing child object in JSON data from controller - angularjs

I'm creating a laravel application and I'm trying to access a child object's properties in my view using Angular. I can get the whole data in my view (including child objects), but I'm having trouble when trying to display it using Angular.
controller:
public function index(Request $request)
$lang = $request->input('lang') ?? 'pt';
$interestTranslations = Interest::with([
'interesttranslations' => function($query) use ($lang) {
$query->where('languageCode', $lang);
}
])->get()->toArray();
return ['translatedInterests' => $interestTranslations];
}
}
js file:
app..controller("Interests", function ($scope, $rootScope, HobbiesService) {
var lang = $rootScope.lang;
HobbiesService.newData(lang).then(function (response) {
$rootScope.interests = response["data"].translatedInterests;
});
})
html file (interest.interesttranslations works but interest.interesttranslations.name_or_other_property doesn't):
<p style="color: white;">{{interests}}</p> <!-- this shows the whole json datam including the child objects-->
<div class="no-padding owl-carousel" id="hobbies-container" ng-controller="Interests">
<div ng-repeat="interest in interests">
<img src="/img/about/{{ interest.imageName }}" alt="{{ interest.imageName }}" /> <!--this works-->
<p style="color: white;">{{ interest.interesttranslations.name }}</p> <!--this doesn't work-->
</div>
</div>
json displayed in my view when using {{ interests }}:
[{
"id": 1,
"applicant_id": 1,
"imageName": "friends.png",
"created_at": null,
"updated_at": null,
"interesttranslations": [{
"interest_id": 1,
"languageCode": "pt",
"name": "explorar com amigos",
"created_at": null,
"updated_at": null
}]
}, {
"id": 2,
"applicant_id": 1,
"imageName": "world.png",
"created_at": null,
"updated_at": null,
"interesttranslations": [{
"interest_id": 2,
"languageCode": "pt",
"name": "viajar",
"created_at": null,
"updated_at": null
}]
},
{
"id": 3,
"applicant_id": 1,
"imageName": "tv-shows.png",
"created_at": null,
"updated_at": null,
"interesttranslations": [{
"interest_id": 3,
"languageCode": "pt",
"name": "séries televisivas",
"created_at": null,
"updated_at": null
}]
}
]
Thanks in advance!

The property interesttranslations is an array, not an object.
In the view try
{{ interest.interesttranslations[0].name }}
Or use an inner ng-repeat to iterate that array
<p ng-repeat="item in interest.interesttranslations">
{{item.name}}
</p>

Related

How can I get the value of nested JSON array in Ionic?

I am new to Ionic and I am trying to display nested list. I am using JSON response from the server to get all the values. This is my server response.
{
"addonCategories": [
{
"id": 24,
"name": "Cooking type",
"parent_id": 0,
"product_category": 10,
"selection": "single",
"type": "other",
"order": null,
"shows_selection": true,
"selection_type": true,
"direct_pricing": false,
"is_size": false,
"addonItems": [
{
"id": 725,
"name": "Lightly Done",
"product_id": 0,
"addon_category_id": 24,
"price": 0,
"image": "",
"attribute": null,
"main_category_id": 24,
"half_image": null,
"full_image": null,
"order": null,
"large_price": "",
"description": null,
"default_sauce": 0,
"restaurants_id": 0
},
{
"id": 723,
"name": "Regular",
"product_id": 0,
"addon_category_id": 24,
"price": 0,
"image": "",
"attribute": null,
"main_category_id": 24,
"half_image": null,
"full_image": null,
"order": null,
"large_price": "",
"description": null,
"default_sauce": 0,
"restaurants_id": 0
},
{
"id": 724,
"name": "Well Done",
"product_id": 0,
"addon_category_id": 24,
"price": 0,
"image": "",
"attribute": null,
"main_category_id": 24,
"half_image": null,
"full_image": null,
"order": null,
"large_price": "",
"description": null,
"default_sauce": 0,
"restaurants_id": 0
}
]
}
]
}
I am using following HTML code to display nested list with checkbox selection.
<ion-list class="setting-content">
<ion-list-header *ngFor="let item of (addonDetail | async)?.addonCategories" no-lines>{{item.name}}
<ion-item-group class="fst-group">
<ion-item *ngFor="let item1 of item.addonItems" no-lines>
<ion-label >{{item1.name}}</ion-label>
<ion-checkbox (click)="clickAddon(item1)" item-right></ion-checkbox>
</ion-item>
</ion-item-group>
</ion-list-header>
</ion-list>
So how can I get the names from inner JSON array addonItems?
When I run the code it gives me the names from main array (addonCategories) but not from the inner one (addonItems).
The issue is the structure of your HTML template - in short, when you have an ion-list-header, it attempts to render the text for that header in an ion-label. The presence of your nested ion-label (within your ion-item) thus breaks the template.
Instead, and per the Ionic documentation here, your ion-list-header should not contain any child ion-item elements: https://ionicframework.com/docs/api/components/item/Item/#advanced
If instead you restructure your HTML template like this, it will work:
<ion-list class="setting-content">
<ng-container *ngFor="let item of addonCategories">
<ion-list-header no-lines>{{item.name}}</ion-list-header>
<ion-item-group class="fst-group">
<ion-item *ngFor="let addOn of item.addonItems" no-lines>
<ion-label>{{addOn.name}}</ion-label>
<ion-checkbox (click)="clickAddon(addOn)" item-right></ion-checkbox>
</ion-item>
</ion-item-group>
</ng-container>
</ion-list>
Notice on line 3 that the ion-list-header is opened & closed.
Because of the need for nested *ngFor directives - which I'm guessing is why you tried to embed your ion-item elements in the header - I've used the ng-container instead. This way, you can still iterate through each "header" item's array of nested addonItems.
Working Plnkr here: https://embed.plnkr.co/RSd1MdmajLxpdZmTHk8J/

Complicated sorting with tabs in ng-repeat?

I have the following JSON object:
$scope.projects = [
{
"_id": "58ab1cb6edf5430e9014e2bc",
"name": "Project 1",
"issues": [
{
"status": 0,
"name": "Hart Cummings"
},
{
"status": 1,
"name": "Kinney Leach"
},
{
"status": 2,
"name": "Blake Mclaughlin"
}
]
},
{
"_id": "58ab1cb6d87456482e0eec4a",
"name": "Project 2",
"issues": [
{
"status": 0,
"name": "Vargas Gordon"
},
{
"status": 1,
"name": "Bobbie Church"
},
{
"status": 2,
"name": "Pennington Fry"
}
]
},
{
"_id": "58ab1cb6d87456482e0eec4a",
"name": "Project 3",
"issues": [
{
"status": 0,
"name": "WWWWW"
},
{
"status": 1,
"name": "SFSF"
},
{
"status": 2,
"name": "Pennington Fry"
}
]
}
];
I use ng-repeat to display this object in template:
<div ng-app="app">
<div ng-controller="TodoListController">
<div ng-repeat="project in projects">
<br>
<br>
<div><b> {{project.name}}</b></div>
<div class="tabs">
<div style="display:inline" ng-click="sort(1, $index);">Active</div> |
<div style="display:inline" ng-click="sort(0, $index);">Deactivated</div>
</div>
_____________________________________
<div ng-repeat="issue in project.issues | filter: (filterObject.index | filterObject.status)">
<div>{{issue.name}}</div>
</div>
</div>
</div>
</div>
So, as you can see I have two nested ng-repeat.
Issue is:
When I click on any tab and call method sort() I need to sort issue in project.issues by status field.
This is real sample that I want to reach.
https://jsfiddle.net/at6kw67g/
Problem is in this code:
<div ng-repeat="issue in project.issues | filter:filterObject.index : {status : filterObject.status}">
Since the links should sort the issues of a specific project, you should pass the project as argument to your sort() function.
And JavaScript arrays have a sort() method, so just use it.
Since one link should sort issues in ascanding order, and the other one in descending order, you should also pass this information to your sort() function.
So it boils down to
$scope.sortIssuesByStatus = function(project, descending) {
project.issues.sort(function(issue1, issue2) {
var result = issue1.status - issue2.status;
if (descending) {
result = -result;
}
return result;
});
}
and
<div ng-repeat="project in projects">
<div class="tabs">
<button ng-click="sortIssuesByStatus(project, true)">Active</button>
<button ng-click="sortIssuesByStatus(project, false)">Deactivated</button>
</div>
<div ng-repeat="issue in project.issues">
<div>{{issue.name}} - {{ issue.status }}</div>
</div>
</div>
Here's a plunkr implementing it.

AngularJS Recursive Data Structure Traversal with Unique Keys and Arrays

I believe this question is unique in that I am attempting to traverse a data structure containing objects with unique keys and arrays. I've seen other questions regarding this subject, but they reference simple data structures with multiple levels the same object.
Ultimately, I would like to be able to generate a form from any given data structure simply by traversing it as an object or an array.
I've created two directives, one for traversing an object and the other for traversing an array. Basically I'm trying to pass in the array or object as a parameter into the directive's isolated scope, then generate the associated form fields by referencing the scope variable scope.context. I'm not getting any errors, but I'm also not getting the expected result.
Am I approaching this the right way?
Any thoughts or suggestions would be greatly appreciated.
HTML
<div ng-app="app" ng-controller="CreateFormController">
<div traverse-object="{{model.form}}"></div>
<script type="text/ng-template" id="traverseObject.tmpl.html">
<div ng-repeat="(key, value) in context">
<div ng-switch="getTypeOf(value)">
<div ng-switch-when="string">
{{key}} string
</div>
<div ng-switch-when="null">
{{key}} null
</div>
<div ng-switch-when="object">
{{key}} object
<div traverseObject = "{{value}}"></div>
</div>
<div ng-switch-when="array">
{{key}} array
<div traverseArray = "{{value}}"></div>
</div>
<div ng-switch-default="true">
{{key}} other
</div>
</div>
</div>
</script>
<script type="text/ng-template" id="traverseArray.tmpl.html">
<div ng-repeat="item in context">
<div ng-switch="getTypeOf(item)">
<div ng-switch-when="string">
{{item}}
</div>
<div ng-switch-when="null">
{{item}}
</div>
<div ng-switch-when="object">
<div traverseObject = "{{item}}"></div
</div>
<div ng-switch-when="array">
<div traverseArray = "{{item}}"></div>
</div>
<div ng-switch-default="true">
{{item}}
</div>
</div>
</div>
</script>
</div>
JS
var json = {
"ProjectName": null,
"ProjectNumber": null,
"BillingAU": null,
"BillingMailCode": null,
"BorrowersName": null,
"Comment": null,
"CompanyNumber": null,
"DesiredDeliveryDate": null,
"LendingGroup": "",
"LendingOffice": null,
"LoanAmount": null,
"LoanAmountOther": null,
"LoanCloseDate": null,
"LoanNumber": null,
"LoanTerm": null,
"Obligor": null,
"OriginatingAU": null,
"PreviousProjectNumber": null,
"PreviousReport": null,
"TransactionComments": null,
"IsInvolvement": null,
"InvolvementType": "",
"IsFFESecured": null,
"IsJuniorLien": null,
"IsParticipationLoan": null,
"IsWithCrossCollateral": null,
"IsWithLoanGuarantor": null,
"TotalParticipationLoanAmount": null,
"LienPosition": null,
"LoanExist": "",
"LoanType": "",
"OtherLien": null,
"PriorityApproval": "",
"ProjectPurpose": "",
"LoanTransType": "",
"ServiceRequestPeople": [
{
"PersonType": "Account Officer",
"FirstName": null,
"LastName": null,
"Email": null,
"Company": null,
"CompanyNumber": null,
"ImportUserId": null,
"PhoneNumber": "",
"OtherNumber": "",
"FaxNumber": "",
"Address": {
"StreetAddress": "",
"StreetAddress2": "",
"City": "",
"State": "",
"ZipCode": "",
"County": "",
"Nation": "United States",
"Links": []
},
"Links": []
}
],
"Properties": [
{
"DevelopmentName": null,
"PropertyTypesMajor": "",
"PropertyTypes": "",
"PropertyAddress": {
"StreetAddress": "",
"StreetAddress2": "",
"City": "",
"State": "",
"ZipCode": "",
"County": "",
"Nation": "United States",
"Links": []
},
"PropertyDescription": null,
"PropertyCondition": "",
"PropertyRemark": null,
"PropertyStatus": "",
"PropertyTenancy": "",
"ExternalReferenceNumber": null,
"FhaCaseNumber": null,
"LegalComment": null,
"NumberOfBuildings": null,
"NumberOfTenants": null,
"NumberOfUnits": null,
"Occupancy": null,
"PriorSaleDate": "",
"PriorSalePurchaseAmount": null,
"TotalPurchaseAmount": null,
"ProposedUse": null,
"CurrentUse": null,
"Stories": null,
"YearBuilt": null,
"YearLastRenovate": null,
"RentableArea": null,
"Zoning": null,
"ZoningCodeDescription": null,
"MapNumber": null,
"IsForSale": null,
"ListSaleAmount": null,
"IsLegalDescription": null,
"IsPendingSale": null,
"PendingSaleAmount": null,
"PendingSaleDate": "",
"IsRenovationDemo": null,
"RenovationDemoDescription": null,
"IsFloodPlain": null,
"FloodPlainDescription": null,
"FloodPlainSurveyed": null,
"IsGroundLease": null,
"ParkingType": [
""
],
"PrimaryImprovement": {
"Measurement": 0,
"Unit": "",
"Links": []
},
"SecondaryImprovement": {
"Measurement": 0,
"Unit": "",
"Links": []
},
"LandSize": {
"Measurement": 0,
"Unit": "",
"Links": []
},
"ExcessLandSize": {
"Measurement": 0,
"Unit": "",
"Links": []
},
"PropertyParcel": [
{
"ParcelNumber": null,
"Size": 0,
"Links": []
}
],
"PropertyPeople": [
{
"PersonType": "",
"FirstName": null,
"LastName": null,
"Email": null,
"PhoneNumber": "",
"OtherNumber": "",
"FaxNumber": "",
"Affiliation": null,
"Links": []
}
],
"Services": [
{
"ServiceType": null,
"Comments": null,
"SentDate": "",
"DesiredDeliveryDate": "",
"Links": []
}
],
"Links": []
}
],
"Links": []
}
var app = angular.module('app', [])
app.controller('CreateFormController', function($scope){
$scope.model = {}
$scope.model.form = json
})
app.directive("traverseObject", function(){
return {
scope: {
traverseObject: '#'
},
templateUrl: 'traverseObject.tmpl.html',
link: function(scope){
scope.getTypeOf = function(value){
if(value === null) {
return "null";
}
if(Array.isArray(value)) {
return "array";
}
return typeof value;
}
scope.context = JSON.parse(scope.traverseObject)
}
}
})
app.directive("traverseArray", function(){
return {
scope: {
traverseArray: '#'
},
templateUrl: 'traverseArray.tmpl.html',
link: function(scope){
scope.getTypeOf = function(value){
if(value === null) {
return "null";
}
if(Array.isArray(value)) {
return "array";
}
return typeof value;
}
scope.context = JSON.parse(scope.traverseArray)
}
}
})

How to display nested objects and or arrays in angular 2

I am getting json data from the back-end(api). And i want to display this with ngFor. I got an error message like: "Cannot find a differ supporting object '[object Object]'" from the console.
later I tried this:
#Pipe({
name: 'mapToIterable'
})
export class MapToIterable implements PipeTransform{
transform(map: {}, args: any[] = null): any {
if (!map)
return null;
return Object.keys(map)
.map((key) => ({ 'key': key, 'value': map[key] }));
}
}
and then in my view:
<li *ngFor="let detail of getEventDetails | mapToIterable">
Creator Email: {{detail.creator.email}}
</li>
this time i didn't get an error but there is no display values of {{detail.creator.email}}
Data from back-end
{
"banner_image": null,
"categories": [],
"creator": {
"email": "email#email.com",
"first_name": "Prince",
"gender": true,
"id": 15,
"last_name": "Odame",
"subscribed_categories": [],
"watchlist": []
},
"creator_id": 15,
"description": "Learn how to install solar panels in 3 days and make real money all your lifetime",
"faqs": [],
"id": 6,
"is_verified": true,
"max_tickets_per_user": 1,
"shows": [
{
"address": "Engineering Auditorium, College of Engineering, KNUST, Kumasi",
"city": "Kumasi",
"country": "Ghana",
"end_time": "2016-08-03T14:30:00+00:00",
"event_id": 6,
"id": 5,
"is_online": false,
"start_time": "2016-08-01T08:30:00+00:00",
"state": "Ashanti",
"ticket_types": [],
"venue": "Engineering Auditorium"
}
],
"tags": [],
"title": "Solar Panels Installation Workshop"
}
Thanks in advance
You probably just want to do this:
<li>Creator Email: {{getEventDetails.creator.email}}</li>
And for the arrays:
<li *ngFor="let show of getEventDetails?.shows">
Show ID: {{show.id}}
</li>

filter multiple fields using single input in AngularJS

I have a JSON object which is as follows
[{
"id": 1,
"firstName": "Jennifer",
"middleName": null,
"lastName": "Aniston",
"address": "New York City",
}, {
"id": 2,
"firstName": "Angelina",
"middleName": null,
"lastName": "Jolie",
"address": "Beverley Hills",
}, {
"id": 3,
"firstName": "Emma",
"middleName": null,
"lastName": "Watson",
"address": "London",
}]
I'm populating this data in view using ng-repeat.
<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>
Now I have an input box which I'd like to use to filter these names. I would like to use same input box to filter firstName and then filter lastName and don't filter anything else (eg. address).
<input type="text" placeholder="Filter" ng-model="filterBeauties.firstName">
Any idea how can I achieve it?
Try this fiddle.
Essentially, I created a sub-structure for filtering within the data structure being displayed and filter only on that property (e.g. 'filterTerms'):
HTML:
<div ng-controller="MyCtrl">
<input type="text" ng-model="search.filterTerms">
<table border="1">
<tr ng-repeat="row in list | filter:search">
<td>{{row.firstName}} {{row.lastName}}</td>
</tr>
</table>
</div>
JavaScript:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.list = [{
"id": 1,
"address": "New York City",
"firstName": "Jennifer",
"middleName": null,
"lastName": "Aniston",
"filterTerms": {
"firstName": "Jennifer",
"middleName": null,
"lastName": "Aniston",
}
}, {
"id": 1,
"address": "New York City",
"firstName": "Jennifer",
"middleName": null,
"lastName": "Leela",
"filterTerms": {
"firstName": "Jennifer",
"middleName": null,
"lastName": "Leela",
}
}, {
"id": 2,
"address": "Beverley Hills",
"firstName": "Angelina",
"middleName": null,
"lastName": "Jolie",
"filterTerms": {
"firstName": "Angelina",
"middleName": null,
"lastName": "Jolie",
}
}, {
"id": 3,
"address": "London",
"firstName": "Emma",
"middleName": null,
"lastName": "Watson",
"filterTerms": {
"firstName": "Emma",
"middleName": null,
"lastName": "Watson",
}
}];
}
You could simplify this even further for this case by putting all the names into one field (see fiddle here:
HTML:
<div ng-controller="MyCtrl">
<input type="text" ng-model="search.filterTerm" />
<table border="1">
<tr ng-repeat="row in list | filter:search">
<td>{{row.first}} {{row.last}} {{row.address}}</td>
</tr>
</table>
</div>
JavaScript:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.list = [{
"id": 0, "first": "Jenny", "last": "Sorenson", "address": "123 W. Wallnut St.",
"filterTerm": "Jenny Sorenson"
},{
"id": 0, "first": "Susan", "last": "Hinkle", "address": "456 W. Doorbell Dr.",
"filterTerm": "Susan Hinkle"
},{
"id": 0, "first": "Rachel", "last": "Karlyle", "address": "789 W. Sunset Blvd.",
"filterTerm": "Rachel Karlyle"
},{
"id": 0, "first": "Gwen", "last": "Lippi", "address": "0 W. Silly Cir.",
"filterTerm": "Gwen Lippi"
}]
}
Considering that your user have this form:
{
"id": 2,
"firstName": "Angelina",
"middleName": null,
"lastName": "Jolie",
"address": "Beverley Hills"
}
If you want to search one of your user by his firstname, his lastname or both at the same time, you need to concat them together.
$scope.query = '';
$scope.search = function (user) {
var query = $scope.query.toLowerCase(),
fullname = user.firstName.toLowerCase() + ' ' + user.lastName.toLowerCase();
if (fullname.indexOf(query) != -1) {
return true;
}
return false;
};
This function will return true if the current user satisfies your query and false if not. Inside of the function, I recommend to put your query in lowercases so you won't have to deal with the uppercases your user will enter in the search input.
Here is the HTML:
<input type="text" placeholder="Search" ng-model="query">
<table>
<tr ng-repeat="user in users | filter:search">
<td>{{user.firstName}} {{user.lastName}}</td>
</tr>
</table>
This technic will only work if you try to search Angelina Jolie, Angelina, Jolie or even InA JOLIe (why not after all). If you try to search first the lastname like Jolie Angelina, it won't work. You can easily fix it by creating a second fullname in your function (e.g. a reverseFullname), concat in first the lastName and then the firstName and test it just like the first fullname string.
Okay So this is what I did to solve it.
I added a new item in json object (using angular.forEach function) and filtered by it.
$scope.list = beauties.query(function(response) {
angular.forEach(response, function(value, key) {
var fullName = value.firstName + ' ' + value.lastName;
$scope.list[key].fullName = fullName;
});
});
input box code:
<input type="text" placeholder="Filter" ng-model="filterBeauties.fullName">
ng-repeat
<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>
You can pass the third argument to the filter function:
$filter('filter')(list, {'firstName':search});
I would have done something like below:
<input type="text" ng-model="search">
<table border="1">
<tr ng-repeat="row in list | filterBoth:search">
<td>{{row.firstName}} {{row.lastName}}</td>
</tr>
</table>
And then write the custom filter as:
myApp.filter('filterBoth', function($filter) {
return function(list, search) {
if (!search) return list;
var arrSearch = search.split(' '),
lookup = '',
result = [];
arrSearch.forEach(function(item) {
lookup = $filter('filter')(list, {'firstName': item});console.log(lookup);
if (lookup.length > 0) result = result.concat(lookup);
});
return result;
};
});
Demo: http://jsfiddle.net/wAp4S/1/
The only issue is you will get duplicate rows as you are concatenating two similar arrays which can easily be fixed using _.uniq underscore.js method.
Try the angular-filter library instead of writing complex filters. The searchField filter can be helpful here.
https://github.com/a8m/angular-filter
CONTROLLER
$scope.users = [
{ first_name: 'Sharon', last_name: 'Melendez' },
{ first_name: 'Edmundo', last_name: 'Hepler' },
{ first_name: 'Marsha', last_name: 'Letourneau' }
];
HTML
<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
{{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->
Good Luck.

Resources