AngularJS ng-repeat only for Items with a Specific Subfield - angularjs

How can I get ng-repeat to only repeat items which contain subfields? I have a list of videos that updates based on language preference. I want to do something like ng-repeat="video in videos" only where ng-show="video.title[videoLanguage]" would make the element show. When I try using ng-show, it works somewhat but I have other code that works based on the length of the videos list (which updates since not all the videos are available in every single language).
Here's my code:
<ul ng-init="select=0" ng-style="{'margin-top': ((videoContainerHeight - (videos.length * 160)) / (videos.length - 1)) * select}">
<li ng-repeat="video in videos" ng-class="{'selected': select == $index}" ng-click="$parent.select=$index; changeNextPage(video.url);">
<div class="thumbnail"></div>
<div class="title">
<div class="title-cell">
<h2 ng-bind="video.title[videoLanguage]"></h2>
</div>
</div>
</li>
</ul>
Videos list object:
{
"id": "videos",
"url": "/videos",
"view": "views/videos.html",
"nextPage": "#/home",
"videos": [{
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Short Title"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Longer Title Here",
"spanish": "Hi"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "This is a Really Really Really Long Title",
"spanish": "Hi"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Short Title",
"spanish": "Hi"
}
}]
}
I'm looking to have ng-repeat generate a 4 item list when the language is set to english and a 3 item list when the language is set to Spanish.

I have created a fiddle , I think this is exactly what you want, ahve a look
https://jsbin.com/dinuku/edit?html,js,output
I created a filter to filter items based on language
app.filter('languageFilter', function() {
return function(array, lang) {
return (array || []).filter(function(item) {
if (lang in item.title) {
return true;
}
return false;
});
};
});

I suggested you the ng-switch
ng-switch doc

Related

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.

Angular2 Iterating ngFor JSON-File

I´m fairly new to Angular2, and i want to read out a json file. It´s working, that I get the file from a REST-Client, i can save the file in a local variable in a component. Now I´m trying to read properties (Array) with ngFor, but this isn´t working.
Here´s the html:
<div *ngFor="let categories of tasks.tasks">
{{categories}} --> Display name of categorie (epg, recs)
<p *ngFor="let task of categories">{{task.text}}</p>
</div>
And the JSON-File:
{
"tasks": {
"epg": [{
"text": "\\\\...\\Daten\\Videos\\Aufnahmen"
}, {
"text": "C:\\Users\\...\\Desktop"
}],
"recs": [{
"text": "\\\\...\\Daten\\Videos\\Aufnahmen"
}, {
"text": "C:\\...\\Junias\\Desktop"
}]
}
}
Hope someone can help me ;)
Consider
z={
"tasks": {
"epg": [{
"text": "\\\\...\\Daten\\Videos\\Aufnahmen"
}, {
"text": "C:\\Users\\...\\Desktop"
}],
"recs": [{
"text": "\\\\...\\Daten\\Videos\\Aufnahmen"
}, {
"text": "C:\\...\\Junias\\Desktop"
}]
}
Modify your JSON as
let a=this.z.tasks;
this.z = Object.keys(a).map(function(k) { return a[k] });
Here is a plunker

Angularjs nested json object with ng-repeat not working at ionic

First of all, I'm pretty new to the ionic and angularjs. Now I trying to develop a app and i'm having trouble displaying and searching data right now.
I have a nested json object and I cannot display it with ng-repeat.
Here is the json object.
$scope.nestedTestdata = [{
"leadlist ": [{
"submitted_date": "01-01-2160",
"submission_value": {
"full_name": "Full Name ",
"phone": "This is test data.",
"source": "I hate you"
}
},
{
"submitted_date": "01-01-2015",
"submission_value": {
"full_name": "full name",
"phone": "phone.",
"source": "I really really hate you"
}
},
{
"submitted_date": "01-01-2016",
"submission_value": {
"full_name": "I am awesome",
"phone": "HP phone.",
"source": "I hate you"
}
}]
}];
Here is how I display.
<div class="lead_row" ng-repeat="data in nestedTestdata.leadlist | filter: model.search" >
<div class="lead_col">{{data.submitted_date | date : 'dd-MMM-yyyy'}}</div>
<div class="lead_col">{{data.submission_value.source}}</div>
<div class="lead_col">{{data.submission_value.full_name}}</div>
<div class="lead_col">{{data.submission_value.phone}}</div>
</div>
When I change it to following json object, it can display and search function also working.
$scope.testdata = [{
"submitted_date": "01-01-2160",
"submission_value": {
"full_name": "Search is working",
"phone": "This is fucking test data.",
"source": "I hate you"
}
},
{
"submitted_date": "01-01-2015",
"submission_value": {
"full_name": "Fucking full name",
"phone": "Fucking phone.",
"source": "I really really hate you"
}
},
{
"submitted_date": "01-01-2016",
"submission_value": {
"full_name": "I am awesome",
"phone": "Fucking HP phone.",
"source": "I hate you"
}
}];
So I think it is not displaying problem.
Please help to figure out how can i make this work.
Please check inside the following link for the full code.
http://play.ionic.io/app/720567016712
Thank you so much in advance.
nestedTestData contains an array. Inside the array, there is an object.
ng-repeat="data in nestedTestdata[0].leadlist | filter: model.search"
SO code should be as follows:
<div class="lead_row" ng-repeat="data in nestedTestdata[0].leadlist | filter: model.search" >
<div class="lead_col">{{data.submitted_date | date : 'dd-MMM-yyyy'}}</div>
<div class="lead_col">{{data.submission_value.source}}</div>
<div class="lead_col">{{data.submission_value.full_name}}</div>
<div class="lead_col">{{data.submission_value.phone}}</div>
</div>
So you have an array then you are defining another array with an object with a key of 'leadlist'. The answer above could solve your problem or you could just remove the array above your key you can just access it as normal data.nestedTestData
Below is how you could rewrite it:
`$scope.nestedTestdata = {
"leadlist" : [{
"submitted_date": "01-01-2160",
"submission_value": {
"full_name": "Full Name ",
"phone": "This is test data.",
"source": "I hate you"
}
},
{
"submitted_date": "01-01-2015",
"submission_value": {
"full_name": "full name",
"phone": "phone.",
"source": "I really really hate you"
}
},
{
"submitted_date": "01-01-2016",
"submission_value": {
"full_name": "I am awesome",
"phone": "HP phone.",
"source": "I hate you"
}
}]
};`
You can use nested ng-repeat, It will also work if there are multiple objects in $scope.nestedTestdata.
Here is working fiddle
<div ng-controller="MyCtrl">
<div class="lead_row" ng-repeat="data in nestedTestdata">
<div ng-repeat="list in data.leadlist">
<div class="lead_col">{{list.submitted_date | date : 'dd-MMM-yyyy'}}</div>
<div class="lead_col">{{list.submission_value.source}}</div>
<div class="lead_col">{{list.submission_value.full_name}}</div>
<div class="lead_col">{{list.submission_value.phone}}</div>
</div>
</div>
</div>
please remove the space after "leadlist "

AngularJS displaying hierarchical data

I'm trying to display a list of data in a hierarchical view.
My data looks something like this:
items:[
{
"model_id": "1",
"model_type_id": "1",
"name": "Parent 1",
"model_parent_id": ""
},
{
"model_id": "2",
"model_type_id": "1",
"name": "Parent 2",
"model_parent_id": ""
},
{
"model_id": "3",
"model_type_id": "2",
"name": "Child 1",
"model_parent_id": "1"
},
{
"model_id": "4",
"model_type_id": "2",
"name": "Child 2",
"model_parent_id": "2"
}
]
My controller looks like:
myApp.controller('ModelController', ['$scope', 'ModelFactory',
function ($scope, ModelFactory) {
$scope.init = function (id) {
$scope.brandId = id;
getModels($scope.brandId);
};
function getModels(brandId) {
ModelFactory.GetModels(brandId)
.success(function (mdls) {
$scope.models = mdls;
console.log($scope.mdls);
})
.error(function (error) {
$scope.status = 'Unable to load model data: ' + error.message;
console.log($scope.status);
});
};
}
]);
My HTML looks like:
<div ng-controller="ModelController" ng-init="init(brand.ID)">
<ul ng-sortable class="block__list block__list_words">
<li ng-repeat="model in models | filter: {model_type_id:1} ">{{model.model_name}} - {{model.model_id}}
<div ng-controller="ModelController" ng-init="init(brand.ID)">
<ul ng-sortable class="block__list block__list_words">
<li ng-repeat="m in models | filter: {model_type_id:2} | filter:{model_parent_id:model.model_id}">
{{m.model_name}} - {{m.model_parent_id}}
</li>
</ul>
</div>
</li>
</ul>
</div>
The filter isn't working where I'm trying to filter on the inner controller with the outer controller. I'm getting both children displayed below each parent. How can I get it so the parent is displayed, and only the children are displayed where the childs model_parent_id equals the model_id of the parent?
While I'm not sure whether there is a way to achieve this using filter, the normal way to display nested data is to reorganize the data structure to reflect what you want to display.
items:[
{
"model_id": "1",
"model_type_id": "1",
"name": "Parent 1",
"children": [{
"model_id": "3",
"model_type_id": "2",
"name": "Child 1"
}]
},
{
"model_id": "2",
"model_type_id": "1",
"name": "Parent 2",
"children": [{
"model_id": "3",
"model_type_id": "2",
"name": "Child 2"
}]
}
]
And then display them using nested ng-repeat
<ul>
<li ng-repeat="parent in items">
{{parent.name}} - {{parent.model_id}}
<ul>
<li ng-repeat="child in parent.children">
{{child.name}} - {{child.model_id}}
</li>
</ul>
</li>
</ul>
Note: There is no need to use nested controllers, just one on the top layer should be enough. If you need to use some shared logic recursively, use a custom directive to replace the li.
To reorganize the data you can do either on the server side or client side.
The following shows how to do in client side as we might not have the permission to change the server side API.
$scope.data = [];
angular.forEach(items, function(item) {
if (item.model_parent_id == "") {
$scope.data.push(item);
}
});
// add all parents first in case some children comes before parent
angular.forEach(items, function(item) {
if (item.model_parent_id == "") continue;
// search for parent
angular.forEach($scope.data, function(parent) {
if (parent.model_id == item.model_parent_id) {
if (!parent.children) parent.children = [];
parent.children.push(item);
}
}
});

Dropdown inside select in angular js

I have the following JSON object :
[{
"Question": "Sample question One",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Two",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Three",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No",
}, {
"OptionId": 3,
"Option": "May be",
}]
}]
I am using a select with ng-options to iterate each question. Inside the select I am adding a dropdown with the options binded to it.
This is works properly.
Now I have to hide a div if the option selected for the second question is no and if the option selected is yes, i have to show the div.
I tried using ng-show and ng-hide based on a model property "isDetailsVisible". I thought it would be easy to bind this to the second question's answer but I am unable to think of a way to do this.
Does anyone have ideas?
This may help you I think,
In this I have seperated the display as follows
Custom directive questioninfo: for displaying the information about the selected question. This also shows the options of the selected question, but before iterating, i use filter on the options to get only available options(with value 'Yes')
Filter optionFilter: For filtering the options, I have applied the filter to select options with given value('Yes') in 'Option'
var app = angular.module('plunker', []);
app.factory('dataService', function() {
return {
data: {
"Questions": [{
"Question": "Sample question One",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Two",
"Options": [{
"OptionId": 1,
"Option": "No"
}, {
"OptionId": 2,
"Option": "No"
}]
}]
}
};
});
// I am using this filter because options should not be many
app.filter('optionFilter', function() {
return function(items, value) {
if (!angular.isUndefined(items)) {
var arrayToReturn = [];
for (var i = 0; i < items.length; i++) {
if (items[i].Option === value) {
arrayToReturn.push(items[i]);
}
}
return arrayToReturn;
}
};
});
app.directive('questioninfo', function() {
return {
restrict: 'AE',
scope: {
selectedQuestion:'=question'
},
controller: function($scope) {},
template: '<h2>{{selectedQuestion.Question}}</h2>\
<h3>Available Options</h3>\
<div ng-repeat="option in selectedQuestion.Options|optionFilter:\'Yes\'"> \
<div ng-if="shouldShowOption(option)"><b>Option {{option.OptionId}}</b> {{option.Option}}</div>\
</div>\
\
'
};
})
app.controller('MainCtrl', function($scope, dataService) {
$scope.name = 'World';
$scope.data = dataService.data;
$scope.Questions = dataService.data.Questions;
$scope.selectedQuestion = dataService.data.Questions[1].Question;
});
HTML Code:
<body ng-controller="MainCtrl">
<h1>Select Question</h1>
<select id="s1" ng-model="selectedQuestion" ng-options="item as item.Question for item in Questions">
</select>
<h3>The selected item just for reference:</h3>
<pre>{{selectedQuestion | json}}</pre>
<hr>
<questioninfo question="selectedQuestion"></questioninfo>
</body>
</html>
Check this link [Plunker]: http://plnkr.co/edit/LIVVofC8nyYtbYYVBBCb?p=preview
Thanks Ganesh for the detailed answer. I am expecting a little more simpler way.
I think I found an answer. I updated the JSON to make it easier, but this does not impact much.
[{
"Question": "Sample question One",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}, {
"Question": "Sample question Two",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}, {
"Question": "Sample question Three",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}]
on the html, I have the following :
<div class="col-md-12 nopadding" data-ng-repeat="Question in Questions">
<select ng-model="question.SelectedOption" ng-options="option for option in Question.Options"> </select></div>
and for the div which I have to show and hide, I am using ng-show.
<div class="box-3" ng-show="Questions[1].SelectedOption === 'Yes'">
This works fine. But I feel the ng-show should have been mapped to a property or a method so that the logic resides in the controller and not in the html.
I would appreciate any comments on my above approach or any thoughts on how to have this logic moved to controller. Questions are not loaded initially. There is a button click on which the question loads and from that time I want the div to respond to the answer of the
second question. Till the question loads, the div is hidden.

Resources