Only show content associated with user - angularjs

I have a service that does a request,
.factory('movieService', ['$http', function($http) {
return {
loadMovies: function() {
return $http.get('/movies_users.json');
}
};
}])
This is the JSON output and is the result of 2 tables being joined. A user table and a movie table. As you can see the users are associated with 1 or more movies.
[
{"id":1,
"email":"peter#peter.nl",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
},
{
"id":5,
"title":"Star Wars: Episode VII - The Force Awakens",
"movie_id":"140607"
}
]
},
{"id":2,
"email":"jan#jan.com",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
}
]
}
]
I then have this function in my controller,
movieService.loadMovies().then(function(response) {
$scope.movies = response.data;
});
This stores the data from the service into the movie scope.
If I do,
"ng-repeat" => "movie in movies"
The ng-repeat shows all the movies added by all the users. How would I only show the movies associated with the current user in a view?

This seems to be what you want - let me know if it helps.
Note that you have an extra " on movie_id" that is certainly not helping
angular.module('myApp', [])
.controller('ctrl', function($scope) {
$scope.users = [
{"id":1,
"email":"peter#peter.nl",
"movies":[
{
"id":4,
"title":"Creed",
movie_id:"312221"
},
{
"id":5,
"title":"Star Wars: Episode VII - The Force Awakens",
"movie_id":"140607"
}
]
},
{"id":2,
"email":"jan#jan.com",
"movies":[
{
"id":4,
"title":"Creed",
movie_id:"312221"
}
]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
<div ng-repeat="user in users">
{{user.email}}
<div ng-repeat="movie in user.movies">
{{movie.title}}
</div>
</div>
<h2>Movies for user 2</h2>
<div ng-repeat="movie in users[1].movies">
{{movie.title}}
</div>
</div>

Found in a quick google search:
How do I filter an array with AngularJS and use a property of the filtered object as the ng-model attribute?
<div ng-repeat="movie in movies | filter {email:'user#email.com'}">
Edit: it looks like you actually have a list of users, so you could do a filter on an ngrepeat on users, then you'd have a nested ngrepeat on movies (unfiltered because they're attached to a user). But depending on how your app actually needs to work you could just filter the data when it comes back and throw out the users you don't need. Which introduces the question, do you have access to the server side code? If so you could filter there and not return data that is associated with a different user in the first place

Related

How to check if the ng-repeat in view is empty after certain conditions match

I have an object coming from the JSON.
I use ng-repeat to display the object.
In order to show certain rows-only, I use if condition and not filter.
My question is, after I use if condition and if there is none of the rows matching the condition, I need to show an "empty" alert. How can I do that?
As of now my object is like this
[{
"task_id":3773,
"task_name":"King of Avalon: Dragon War",
"task_status":"pending"
},
{
"task_id":2208,
"task_name":"Final Fantasy XV",
"task_status":"pending"
},
{
"task_id":3760,
"task_name":"King of Avalon: Dragon War",
"task_status":"pending"
},
{
"task_id":2746,
"task_name":"Postmates",
"task_status":"complete"
}]
As you can see the column 'task_status'. There are various values to it : 'complete', 'pending', 'new'.
I'm using the following code to display to the 'new' tasks alone.
<div ng-repeat="(key, task) in tasksObj" ng-if="task.task_status == 'new'>
<p>{{task.task_id}}</p>
</div>
How do I display an empty rows error when there is no 'new' tasks available?
You can write that logic in controller where you can check if all the task do not have new status and alert accordingly.
angular.module('app', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.tasksObj = [{
"task_id": 3773,
"task_name": "King of Avalon: Dragon War",
"task_status": "pending"
}, {
"task_id": 2208,
"task_name": "Final Fantasy XV",
"task_status": "pending"
}, {
"task_id": 3760,
"task_name": "King of Avalon: Dragon War",
"task_status": "pending"
}, {
"task_id": 2746,
"task_name": "Postmates",
"task_status": "complete"
}];
let nonNewStatus = $scope.tasksObj.every(({task_status}) => task_status!=='new');
if(nonNewStatus) {
alert('There is no any task with status: new');
}
}])
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="MainCtrl">
<div ng-repeat="(key, task) in tasksObj" ng-if="task.task_status =='new'">
<p>{{task.task_id}}</p>
</div>
</div>

Access images from local JSON file on the web page in angularjs

Where am i going wrong?
I want to access images from datahl.json file on the web page but unable to access them.Please check the codes and help me.
If possible please refer the solution to plunker editor.
index.html
<div class="col-sm-4" ng-repeat = "hbl in hbls">
<div class="thumbnail" ng-repeat = "h in hbl.data_list"
style="width:100%;">
<img ng-src="{{h.img}}" alt="" style="height:50vh;">
<div class="caption">
<p><strong>{{h.name}}</strong></p>
</div>
</div>
</div>
app.js This is my js codes
var app = angular.module('hostellApp', []);
app.controller('hostellController', function($scope, hblsFactory){
$scope.hbls;
hblsFactory.getHbls().then(function(response){
$scope.hbls = response.data;
});
$scope.sayHello = function(){
console.log("Hello");
}
});
app.factory('hblsFactory', function($http){
function getHbls(){
return $http.get('datahl.json');
}
return {
getHbls: getHbls
}
});
datahl.json This is my local JSON file
`
{
"view_type": 5,
"title": "Hostels By Locality",
"position": 5,
"data_list":
[
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/IMG_20180526_1139570.8091572935412125.jpg",
"name": "Mahavir Nagar"
},
{
"img": "https://graph.facebook.com/1666751513414902/picture?
type=large",
"name": null
},
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/cropped1148015742983667713.jpg",
"name": "New Rajiv Gandhi"
},
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/cropped998427941.jpg",
"name": "Jawahar Nagar"
}
]
}`
The data you get from your JSON file is not an array but an object. This means that you only need one ng-repeat.
Change your first ng-repeat to ng-repeat="h in hbls.data_list"(added an 's' to hbl) and delete your second ng-repeat.
Working plunker: https://plnkr.co/edit/OOd1M1dNFjSB7uaqZZB6?p=preview

How to submit selected checkboxes and group name as an objects within an array

I need to pass selected checkbox object data alone into array on form submit.
service returning json data:
[
{
"groupName" : "A",
"groups": [
"Painting",
"coloring"
]
},
{
"groupName" : "B",
"groups": [
"drawing",
"writing"
]
}
]
service expected format when user selected couple of check boxes and submit form:
{
"groups": [
{
"category": "A",
"subCategory": "coloring"
},
{
"category": "B",
"subCategory": "writing"
}
]
}
My controller:
<div ng-controller="groupCtrl">
<form class="form" name="form" role="form" ng-submit="groupData()" autocomplete="off" novalidate>
<div ng-repeat="groups in groupsList">
<p class="category">{{groups.groupName}}</p>
<p ng-repeat="group in groups.groups" >
<input type="checkbox" id="group" name="{{group}}" class="group" value="{{group}}" ng-model="groups"> {{group}}
</p>
</div>
<button type="submit" class="button">Save</button>
</form>
Controller:
angular.module('myApp')
.controller("groupCtrl", function($rootScope, $scope, $state, $http) {
$http.get('group.json').success(function(groupsList) {
$scope.groupsList = groupsList;
});
$scope.groups = {
}
$scope.groupData = function () {
$http.post('<service endpoint>', $scope.groups, {
})
.success(function(){
console.log("success");
})
.error(function(){
console.log("failed.");
});
}
});
I am new to angular. Looking for help on how to construct array object in controller and update array object on user select/un-select check boxes.
First I would put api logic into a service like this:
angular.module('myApp', [])
//service to handle api communication
.service('apiService', ['$http', function($http) {
return {
getGroups: function() {
return $http.get('http://superapi.com');
}
}
}])
Then you need to call the api service from the controller and build up your view model:
api.getGroups().then(function(res) {
//JSON.parse will not be needed if your API returns a JSON body with application/json set as content-type
$scope.groupsList = JSON.parse(res.data.data);
//Build up the view model.
$scope.groupsList.forEach(function(g) {
$scope.selectedGroups.groups.push({
category: g.groupName,
subCategory: []
});
});
},
function(error) {
//handle API errors gracefully here.
});
Then you can use ng-model on the form components to populate it with data
<form class="form" name="form" role="form" ng-submit="groupData()" autocomplete="off" novalidate>
<div ng-repeat="groups in groupsList track by $index">
<p class="category">{{groups.groupName}}</p>
<p ng-repeat="group in groups.groups track by $index">
<input ng-model="selectedGroups.groups[$parent.$index].subCategory" type="checkbox" id="group" name="{{group}}" class="group" ng-true-value="'{{group}}'" ng-init="checked=''" ng-false-value="''"> {{group}}
</p>
</div>
<button type="submit" class="button">Save</button>
</form>
Since your api response model has a double nested hierarchy, we need two nested ng-repeat loops. We can then leverage the fact that ng-repeat creates a child scope, and the parent scope is accessible by using $parent. That way we can use that information to bind to the correct part of the view model with ng-model.
ng-model="selectedGroups.groups[$parent.$index].subCategory"
$parent.$index is the first ng-repeat groups in groupsList
If you want to be able to select more than one subcategory, you can just bind nd-model to each subcategory's index in an array like this:
ng-model="selectedGroups.groups[$parent.$index].subCategory[$index]"
This will use the index of the subCategory to bind to a specific position in an array.
here is a working example of that :
https://jsfiddle.net/zzq16t8u/4/
Here is a working JSFiddle for you:
https://jsfiddle.net/zzq16t8u/3/
Now when you want to map to the request model specified by the system, you will need to handle this in the function handled by the form submit. You could do something clever with ng-true-value, but then you would still need to do a JSON.parse on your data, as it can only work on strings. And I my opinion handling the mapping to the request model is better done once you prepare to make the request.
$scope.groupData = function() {
// map data to the request model specified
var requestModel = {
groups: []
};
$scope.selectedGroups.forEach(function(group) {
group.subCategory.forEach(function(subCat) {
requestModel.groups.push({
category: group.category,
subCategory: subCat
});
});
});
Here is a working JSFiddle of everything, note that I have simplified the view model here, since we no longer bind directly to the request model.
https://jsfiddle.net/zzq16t8u/15/
Please note that the JSON.parse is only necessary here, as I was unable to figure out how to get the JSFiddle echo service to return json as real json, and not a string, and the api service in the example uses this echo service to mock a real http response, so that will need to be replace by a real http call - as I showed in this answer.
Hope it helps.

AngularJS: Sharing scope between multiple instances of same directive

I'm writing an app that uses the same table with the same data in multiple places. I created a custom directive that allows me to reuse this table. Unfortunately, if I edit the table in one instance, the other instance does not refresh. How do I link these two so that any edits I make to one show up in the other?
It sounds like you've mostly figured it out, the hard part is getting your data into a shape where the videos and photos can be shared by the slide show. I recommend doing this in a shared data access object returned by a separate factory in Angular, rather than directly in a scope. I've got a sample in Plunkr if it helps.
The sample has a directives that binds to shared data, retrieved from a factory as an object injected into two separate scopes. In your case, you would have to add methods to retrieve data from the server, and shape it for display.
testApp.factory("News", [function () {
var news = {
"stories": [
{"date": new Date("2015-03-01"), "title": "Stuff happened"},
{"date": new Date("2015-02-28"), "title": "Bad weather coming"},
{"date": new Date("2015-02-27"), "title": "Dog bites man"}
],
"addStory": function (title) {
var story = {
"date": new Date(),
"title": title
};
news.stories.push(story);
}
};
return news;
}]);
Both controllers reference the same factory for the data:
testApp.controller("FirstController",
["$scope", "News", function ($scope, news) {
$scope.news = news;
}]);
testApp.controller("SecondController",
["$scope", "News", function ($scope, news) {
$scope.news = news;
}]);
Views then pass the data into to the news list directive, which both shares the data and keeps the directive relatively dumb.
<div ng-controller="FirstController">
<news-list news="news" title="'First List'"></news-list>
</div>
<div ng-controller="SecondController">
<news-list news="news" title="'Second List'"></news-list>
</div>
The news-list directive is just dumb formatting in this example:
testApp.directive("newsList",
function() {
var directive = {
"restrict": "E",
"replace": false,
"templateUrl": "news-list.html",
"scope": {
"news": "=news",
"title": "=title"
}
};
return directive;
});
View template:
<div class="news-list">
<p>{{title}}</p>
<ul>
<li ng-repeat="story in news.stories | orderBy:'date':true">{{story.date | date:'short'}}: {{story.title}}</li>
</ul>
<form>
<input type="text" id="newTitle" ng-model="newTitle" />
<button ng-click="news.addStory(newTitle)">Add</button>
</form>
</div>

JSON Angular Array pulling data from 3rd Loop

I am struggling to pull the data from the 3rd loop (Names) in the array below.
Any idea what i am doing wrong?
sample.json
{
"otc": [
{
"name": "Tums",
"language": [
{
"title": "English",
"names": [
{"name": "Tums"},
{"name": "Pepto"}
]
},
{
"title": "China"
},
{
"title": "Germany"
}
,
{
"title": "Mexico"
}
,
{
"title": "India"
}
,
{
"title": "United Kingdom"
}
]
},
{
"name": "Dramamine",
"language": [
{
"title": "title2album1"
},
{
"title": "title2album2"
},
{
"title": "title2album3"
}
]
}
]
}
And this is my index.html
<body ng-app="list">
<div ng-controller="ListCtrl">
<ul>
<li ng-repeat-start="meds in otc">
<strong> {{meds.name}}</strong> //This displays just fine
</li>
<li ng-repeat="lang in meds.language"><em>{{lang.title}}</em></li> //This displays just fine
<li ng-repeat-end ng-repeat="drugs in lang.names">{{drugs.name}}</li> //This doesnt display
</ul>
</div>
<script>
angular.module('list', []);
function ListCtrl($scope, $http) {
$http({method: 'GET', url: 'sample.json'}).success(function(data) {
$scope.otc = [];
angular.forEach(data.otc, function(value, key) {
$scope.otc.push(value);
});
$scope.isVisible = function(name){
return true;
};
});
}
</script>
It looks like your JSON data is a bit incomplete, since you're missing the names key in all of the language objects except for the English one.
Beyond that, your html/angular-view code is a bit off. The ng-repeat's should be nested inside of one-another. This is done by having the opening/closing html tags that contain the ng-repeat directive completely surround the inner <li> tags.
It's a bit hard to tell, but if you want nested lists, you need to add <ul> tags like in my example below.
I believe your index html should look something like:
<ul>
<li ng-repeat="meds in otc">
<strong> {{meds.name}}</strong> //This displays just fine
<ul>
<li ng-repeat="lang in meds.language">
<em>{{lang.title}}</em>
<ul>
<li ng-repeat="drugs in lang.names">{{drugs.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
The reason why the li ng-repeat tags should be nested is because ng-repeat creates its own isolate scope. Which means that inside of an ng-repeat tag, it only has access to the data made available by the ng-repeat="data in datar" part.
So having:
<li ng-repeat="lang in meds.language"><em>{{lang.title}}</em></li> //This displays just fine
<li ng-repeat="drugs in lang.names">{{drugs.name}}</li> //This doesnt display
as sibling elements, and not the second as a child of the other, the 2nd ng-repeat list does not know what the var lang is. So the drugs in lang.names fails.
Btw, this snippet assumes that the output you want is:
Tums
English
Tums
Pepto
China
Germany
etc
Dramamine
title2album1
title2album2
etc
If you wanted the output as a flat list, you can use the following CSS
ul ul {
padding: 0;
margin: 0;
list-style-type: disc;
}

Resources