AngularJS using ng-show based on grandson json element - json

I have the following json data in my application:
{
"Success":true,
"Error":null,
"Data":{
"VersionId":1,
"SecretaryId":1,
"SecretaryName":"Foo",
"Status":1,
"Schools":[
{
"SchoolId":123456,
"SchoolName":"Equipe de Desenvolvimento do Portal",
"ContractStatus":1,
"TotalTeachers":2,
"TotalStudents":0,
"Grades":[
{
"GradeId":1,
"GradeName":"2º Year",
"TotalStudents":0,
"Classes":[
{
"SelectedYear":{
"AvailableYear":null,
"Contract":null,
"Id":2,
"Canceled":false,
"EngagedAreas":null,
"Registrations":null
},
"Id":2,
"Name":"A",
"TotalStudents":20,
"TotalA3":1,
"StudentsPCD":"1,2,3"
},
{
"SelectedYear":{
"AvailableYear":null,
"Contract":null,
"Id":2,
"Canceled":false,
"EngagedAreas":null,
"Registrations":null
},
"Id":3,
"Name":"B",
"TotalStudents":25,
"TotalA3":0,
"StudentsPCD":"1"
}
]
},
{
"GradeId":2,
"GradeName":"3º Year",
"TotalStudents":0,
"Classes":[
]
},
{
"GradeId":3,
"GradeName":"4º Year",
"TotalStudents":0,
"Classes":[
]
}
]
},
{
"SchoolId":52640002,
"SchoolName":"EscTesRelatDir",
"ContractStatus":0,
"TotalTeachers":0,
"TotalStudents":0,
"Grades":[
{
"GradeId":1,
"GradeName":"2º Year",
"TotalStudents":0,
"Classes":[
]
},
{
"GradeId":2,
"GradeName":"3º Year",
"TotalStudents":0,
"Classes":[
]
}
]
}
]
}
}
I use this json to dynamically create some HTML.
For each school a div is created, this is the first level. For each grade in the school, a table is created, this is the second level. And for each class in the grade a table row is created, this is the third level.
I'm wondering how could I use the ng-show command to show the first level div only if the related school have at least one class.
I've searched a lot, but I couldn't find an answer yet.
EDIT:
Here is my html code.
<div ng-repeat="school in data.schools" ng-show="{{ school.Grades.<AnyClass?>.length > 0 }}">
<h2>{{ school.SchoolName }}</h2>
<span><strong>Total Teachers:</strong> {{ school.TotalTeachers }}</span>
<table ng-repeat="grade in school.Grades" class="table table-bordered table-striped table-condensed" ng-show="{{ grade.Classes.length > 0 }}">
<tbody>
<tr>
<th colspan="4">{{ grade.GradeName }}</th>
</tr>
<tr>
<th>Class</th>
<th>Total Students</th>
<th>Total A3</th>
<th>PCD Students</th>
</tr>
<tr ng-repeat="class in grade.Classes">
<td>{{ class.Name }}</td>
<td>{{ class.TotalStudents }}</td>
<td>{{ class.TotalA3 }}</td>
<td>{{ class.StudentsPCD }}</td>
</tr>
</tbody>
</table>
</div>
EDIT
This is how I'm making my requests:
//rest_client.js
"use strict";
(function(){
var restClient = angular.module("restClient", ["ngResource"]);
var serviceURL = "/habileapp/api/";
restClient.factory("RegistrationResource", ["$resource", function ($resource) {
return $resource(serviceURL + "Registration", null, {
"get": {
"method": "get"
},
"save": {
"method": "post",
"url": serviceURL + "Registration/Save"
},
"finalize": {
"method": "post",
"url": serviceURL + "Registration/Finalize"
}
});
}]);
})();
//part of app.js
RegistrationResource.get({
"idAplicacao": 1,
"idSecretaria": 1
}, function (data) {
if (data.Success) {
$scope.data = data.Data;
runApplication();
} else {
toastr.error(Errors.Code1);
}
hideLoading();
});

I don't think it is possible within your template since you cannot bubble up through the different ng-repeats. But you could add another attribute to each school object whether its Classes array length is greater than 0 within your controller:
//part of app.js
RegistrationResource.get({
"idAplicacao": 1,
"idSecretaria": 1
}, function (data) {
if (data.Success) {
angular.forEach(data.Schools, function(item) {
angular.forEach(item.Grades, function(item2) {
(item2.Classes.length > 0) && item.show = true;
});
});
$scope.data = data.Data;
runApplication();
} else {
toastr.error(Errors.Code1);
}
hideLoading();
});
Then, just add ng-show="show" in your markup.

After getting the data you can change it or add any "helper" properties that you can use to control the elements you want to show or how to show them. Consider the following example which makes any entry red that has a "long title", being more than 40 characters:
HTML template
<body ng-controller="Ctrl">
<b><u>Posts</u></b>
<div ng-repeat="post in posts">
<span ng-class="{ 'red': post.longTitle }">
id:{{ post.id }} title:{{ post.title }}
</span>
</div>
</body>
JavaScript
app.controller('Ctrl', function($scope, $http) {
var url = 'http://jsonplaceholder.typicode.com/posts';
// get data
$http.get(url).then(function(response) {
// take top 10
var data = response.data.slice(0, 10);
// add helper property called "long title" that
// doesn't exists in original data
angular.forEach(data, function(current) {
current.longTitle = current.title.length > 40 ? true : false;
});
// apply
$scope.posts = data;
});
});
CSS
.red {
color: red;
}
Result

Related

Access and modify JSON property using v-model on VUE JS

I generate a JSON with a lot of nested data, one of those properties called 'value' inside 'operations' is used in the v-model of every input of a dynamic generated html table. Initially that property is set to 0 and the input is set with that value but when I change the value in the input it doesn't reflect in the json
The JSON
[
{
"establishment_id":1,
"values":[
{
"capa_id":"A",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"B",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"C",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
]
},
]
The component
Establishments, Operations and CAPA are objects taken from an API via Axios, those data are used to generate the table and the json for the input data
<v-expansion-panels multiple focusable popout class="py-5">
<v-expansion-panel class="expandable" v-for="(establishment, establishmentIndex) in establishments">
<v-expansion-panel-header class="exp_estb">
</v-expansion-panel-header>
<v-expansion-panel-content class="ma-0 pa-0">
<v-row no-gutters>
<v-col cols="12">
<form>
<v-simple-table>
<template>
<thead>
<tr>
<th scope="col">ESTABLECIMIENTO</th>
<th v-for="(operation, index) in operations" scope="col">
{{ operation.description }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(capa, capaIndex) in capas">
<td>{{capa.name}}</td>
<td v-for="(operation, operationIndex) in operations">
<span>{{ operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value }}</span>
<v-row class="pr-5">
<v-col cols="12" class="mr-2 pr-5">
<v-text-field v-model="operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value" label="" color="#7F53DD"></v-text-field>
</v-col>
</v-row>
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</form>
</v-col>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
Computed
computed:
{
operation_data: function()
{
let operation_data=[]
let operationsWithContent=[]
let capasWithOperations=[]
var establishments = Object.values(this.establishments)
var capas = Object.values(this.capas)
var operations = Object.values(this.operations)
operations.forEach(operation => operationsWithContent.push({ operation_id:operation.id, value: 0 }))
capas.forEach(capa => capasWithOperations.push({ capa_id:capa.id, operations:operationsWithContent }))
establishments.forEach( establishment => operation_data.push({ id:establishment.id, values:capasWithOperations}) )
return operation_data
}
},
Is there a specific reason you need a computed here? It seems more logical to fetch your data using a method and saving that result in a variable. Then you can assign the variable to the v-model like you already did in your example and it should work out of the box.
data() {
return {
operation_data: null
}
},
mounted() {
this.fetchData();
},
methods: {
fetchData() {
// Get your data here with axios
this.operation_data = resultOfAxios;
}
}
For your question on why the data doesn't reflect back:
A computed is initially just a getter. You have to manually add a setter for the computed for it to be able to update data.

Error of displaying data in server side datatables (Angular)

I'm fairly new in using Angular. At the moment I'm implementing datatables into a webpage. For that, I'm following this guide: https://l-lin.github.io/angular-datatables/#/basic/server-side-angular-way.
Despite the guide, I gave it my own twist. Resulting in a buggy datatable.
No pagination, all names on one page, data gets lost after searching for a name,..
I make use of forkJoin inside the dtOptions, maybe that's the bug? Anyone got an idea?
My code
export class NewPackageComponent implements OnInit {
dtOptions: DataTables.Settings = {};
pageEvent: PageEvent;
clickedTransactionID: string;
packagesArray: string[]
constructor(public packageToolkitService: PackageToolkitService) { }
ngOnInit(): void {
let that = this;
this.dtOptions = {
pagingType: 'full_numbers',
pageLength: 10,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
forkJoin([that.packageToolkitService.getPackages()])
.subscribe(packages => {
that.packagesArray = packages[0]['packageNames']
})
}
};
}
PackageToolkitService
getPackages() {
return this.http.get(buildUrl('.gui.wmPackage/_get?'), httpOptions);
}
HTML
<table datatable [dtOptions]="dtOptions" class="row-border hover">
<thead>
<tr>
<th>NAME</th>
</tr>
</thead>
<tbody *ngIf="packagesArray?.length != 0">
<tr *ngFor="let package of packagesArray">
<td>{{ package }}</td>
</tr>
</tbody>
<tbody *ngIf="packagesArray?.length == 0">
<tr>
<td colspan="3" class="no-data-available">No data!</td>
</tr>
<tbody>
</table>
JSON GET Response
{
"requestHdrs": {
"Content-Type": "application/json",
},
"packageMap": [
{
"build": "161",
"name": "WmTN",
"description": "Trading Networks",
"version": "10.1.0.0.161"
},
{
"build": "",
"name": "test",
"description": "",
"version": ""
},
{
"name": "be_nrb_rst_shared_party_v2",
"version": "2.0.0"
}
],
"packageNames": [
"WmTN",
"test",
"be_nrb_rst_shared_party_v2"
]
}
Anyone got an idea?

angular - read property name from JSON as column name and show another property value in the column

I have json file in a structure (showing one of its objects) as
[
...
{
"Tag": "YearOfOperation",
"Type": 9,
"Value": "2018"
}
...
]
on html template I have a table. On table's "Year Of Operation" row , I want to display "2018". I am trying to iterate over json (i.e find by row/tag name) and display display "Value" of the json. In html template, I want to have something like:
<table>
<tr>
<td> Year Of Operation </td> // row name is hard coded. it doesn't depend on json
<td> display json "Value" where "Tag"=="YearOfOperation" </td>
</tr>
</table>
app.component.ts
public productData: any;
ngOnInit() {
this.getJSON().subscribe(res => {
this.productData = JSON.parse(res);
})
}
public getJSON(): Observable<any> {
return this.http.get('./images/output_test.json')
.pipe(
map(res => res)
)
// .catch((error:any) => console.log(error));
}
Thank you in advance.
If your JSON is something like below and i understood your question correctly, then this is what should work for you:
app.json
[
{ "Tag":"Location", "type": 9, "Value":"Europe" },
{ "Tag":"Location", "type": 10, "Value":"US" },
{ "Tag":"YearOfOperation", "type": 9, "Value":"2016" },
{ "Tag":"YearOfOperation", "type": 10, "Value":"2018" },
{ "Tag":"TaxId", "type": 9, "Value":"txn123" },
{ "Tag":"TaxId", "type": 10, "Value":"txn124" }
]
app.component.html
<table>
<thead><tr><th>Location</th><th>Year Of Operation</th><th>Tax ID</th></tr></thead>
<tbody>
<tr *ngFor="let product of products">
<td *ngIf="product?.Tag === 'Location'; else blankValue">{{product?.Value}}</td>
<td *ngIf="product?.Tag === 'YearOfOperation'; else blankValue">{{product?.Value}}</td>
<td *ngIf="product?.Tag === 'TaxId'; else blankValue">{{product?.Value}}</td>
</tr>
</tbody>
</table>
<ng-template #blankValue><td></td></ng-template>
app.component.ts
public products: any;
ngOnInit() {
this.getJSON().subscribe(res => {
this.products = <Array<{}>>res;
})
}
public getJSON(): Observable<any> {
return this.http.get('./images/output_test.json')
.pipe(
map(res => res),
catchError((error) => { console.error(error); return error;})
);
}
app.component.css
th {
padding:10px;
border:1px solid black;
}
td {
padding:10px;
border:1px solid black;
}

ajax call and $.watch in Angular

I need to generate a select menu when a button is clicked. I am making an ajax call to get json data from external file, upon button click. which In turn should update the select with data from json. with the code below the select gets updated only after the button is clicked twice. I am watching the jsonData but its not working as expected.
HTML:
<div ng-controller="MainViewCtrl">
<button ng-click="getDeployedResources()"> Load Resources </button>
<select ng-model="selectedOption.name" ng-options="item.name as item.name for item in jsonData"></select>
</div>
json from dropdown.json:
{
"DeployedResources": {
"-env": "dev13",
"ResourceList": {
"-exportTime": 1444999007878,
"Resource": [{
"name": "default",
"type": "project"
},
{
"name": "System",
"type": "project"
},
{
"name": "StratusCommonServices",
"type": "project"
}]
}
}
}
JS:
var app = angular.module('JSONedit', ['ui.sortable'])
.controller('MainViewCtrl', ['$scope', '$http', '$filter','$compile', function ($scope, $http, $filter, $compile) {
$scope.jsonData = {};
$scope.getDeployedResources = function () {
$.ajax({
url: 'json/dropdown.json',
dataType: 'json'
}).done(function (data) {
$scope.jsonData = data.DeployedResources.ResourceList.Resource;
$scope.selectedOption = angular.copy($scope.jsonData[0]);
});
}
$scope.$watch('jsonData', function (json) {
$scope.jsonString = $filter('json')(json);
}, true);
$scope.$watch('jsonString', function (json) {
try {
$scope.jsonData = JSON.parse(json);
$scope.wellFormed = true;
} catch (e) {
$scope.wellFormed = false;
}
}, true);
}])
This is the correct life-cycle of a simple AngularJS Component!
Don't use jQuery for doing something that angular does better!
angular
.module('test', [])
.service('DataService', function($q, $http) {
var self = this;
var mock = {
id: 1,
"DeployedResources": {
"-env": "dev13",
"ResourceList": {
"-exportTime": 1444999007878,
"Resource": [{
"name": "default",
"type": "project"
}, {
"name": "System",
"type": "project"
}, {
"name": "StratusCommonServices",
"type": "project"
}]
}
}
};
self.load = function() {
console.log('loading data', mock.id);
for (var i = 0, len = mock.DeployedResources.ResourceList.Resource.length; i < len; i++) {
mock.DeployedResources.ResourceList.Resource[i].name += mock.id;
}
mock.id += 1;
return $q.when(mock);
return $http
.get('/api/data/')
.then(function(result) {
return result.data;
});
}
})
.controller('TestCtrl', function($scope, DataService) {
var vm = $scope;
vm.select = {
current: null,
items: []
};
vm.loadData = function(event) {
console.count('load data');
return DataService
.load()
.then(function(data) {
vm.current = data.id;
return data.DeployedResources.ResourceList.Resource;
})
.then(function(items) {
vm.select.items = items;
vm.select.current = vm.select.items[0];
})
};
vm.loadData();
});
.select-wrapper {
padding: 1em 2em;
background: yellow;
}
.select-wrapper select {
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<article ng-app="test">
<div ng-controller="TestCtrl">
<button type="button" ng-click="loadData($event);">LoadNew</button>
<div class="select-wrapper">
<select ng-model="select.current" ng-options="item as item.name for item in select.items"></select>
</div>
<div ng-bind="select.items | json"></div>
</div>
</article>

how to populate a drop down menu with data coming to controller using http get in angular js

This is the JSON file ..
Using angular js controller and view how can I parse this json and display the drop1 and drop2 values of respective technology in drop down menu.getting the JSON data using http get.
Thanks in advance
{
"technology": [
{
"id": "AKC",
"detail": {
"drop1": [
{
"id": "AKC-lst-1231"
},
{
"id": "AKC-lst-1232"
},
{
"id": "AKC-lst-1233"
}
],
"drop2": [
{
"id": "T_AKC_live"
},
{
"id": "T_AKC_Capt"
},
{
"id": "T_AKC_live1"
}
]
}
},
{
"id": "MET",
"detail": {
"drop1": [
{
"id": "MET-2st"
},
{
"id": "MET-34"
}
],
"drop2": [
{
"id": "sd-232"
},
{
"id": "sd-121"
}
]
}
}
]
}
Please consider this example:
<!DOCTYPE html>
<html ng-app="postExample">
<head>
<script data-require="angular.js#1.2.22" data-semver="1.2.22" src="https://code.angularjs.org/1.2.22/angular.js"></script>
<script src="usersController.js"></script>
<script src="userRepoService.js"></script>
</head>
<body ng-controller="UsersController">
<h1>Post Angular Example</h1>
<select id="UserSelector" style="width: 100%;">
<option ng-repeat="user in users" value="{{user.id}}">{{user.login}} </option>
</select>
</body>
</html>
userRepoService.js
(function(){
var userRepoService = function($http){
var getUsers = function(username){
return $http.get("https://api.github.com/users")
.then(function(response){
return response.data;
});
};
return {
get: getUsers
};
};
var module = angular.module("postExample");
module.factory("userRepoService", userRepoService);
}());
Controller:
(function(){
var app = angular.module("postExample",[]);
var UsersController = function($scope, userRepoService){
var onFetchError = function(message){
$scope.error = "Error Fetching Users. Message:" +message;
};
var onFetchCompleted = function(data){
$scope.users =data;
};
var getUsers = function(){
userRepoService.get().then(onFetchCompleted,onFetchError);
};
getUsers();
};
app.controller("UsersController", UsersController);
}());
You can directly call $http service, and get that response inside success data parameter.
CODE
$http.get("test.json").
success(function(data, status, headers, config) {
//get data and play with it
}).
error(function(data, status, headers, config) {
alert("Error fetching data");
// log error
});
Hope this could help you, Thanks.