AnguarJS - Nested Array Empty when Accessed - angularjs

I'm going nuts!
My server responds with some JSON at an endpoint. It's something like this:
[{
key: 'value'
nested: [{
key: 'value'
]}
}]
If I access that endpoint directly in my browser, I can confirm I get this properly structured JSON object (from Laravel).
My AngularJS app accesses it like normal:
$http.get('endpoint').success(function(data){
$scope.datas = data;
});
Here's the problem : My object in AngularJS the nested array is always empty unless I return my JSON as a single object instead of an array like this:
{datas: [{
key: 'value'
nested: [{
key: 'value'
]}
}]}
In AngularJS, I can now see the nested array. but wait, if I try to access it like
ng-repeat(data in datas.datas)
It's empty again!.
Here's the Javascript/HTML:
<div ng-repeat="order in orders">
<div ng-repeat="message in order.messages">[[ message.value ]]</div>
</div>
msmService.controller('ordersCtrl', ['$scope', '$http',function($scope, $http){
var refresh = function(){
$http.get('/admin/service/orders').success(function(data){
$scope.orders = data;
});
};
refresh();
});

I rearranged some things and hope this example is what you are looking for:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.orders = {
datas: [
{
key: 'value',
nested: [
{
key: 'nestedValue'
}
]
}
]
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div ng-repeat="order in orders.datas">
{{order.key}}
<div ng-repeat="message in order.nested">{{message.key}}</div>
</div>
</div>

Related

AngularJS - Watch filtered list for changes

Within angular I have a filtered list of people that takes the filter criteria from a predicate function. I want to watch a variable of the filtered list (called filteredPeople) every time the filtered list changes. But I am unable to see when that variable changes.
My code is below:
HTML:
<ul>
<li ng-repeat="person in ($ctrl.filteredPeople = ($ctrl.people | filter: $ctrl.filter))">
...
</li>
</ul>
JS:
controller: ['$scope',
function ($scope) {
var $ctrl = this;
$ctrl.people = {...}
$ctrl.filteredPeople = [];
$scope.$watch($ctrl.filteredPeople, function () {
console.log("called"); //not being called
});
$ctrl.filter = function (p) {
//custom filter function for each item in the array of people
}
}]
I can answer any questions of provide more code if needed
angular.module('app', []).controller('ctrl', function($scope) {
var vm = this;
vm.items = [
{ name: 'Sam' },
{ name: 'Max' },
{ name: 'Tom' },
{ name: 'Henry' },
{ name: 'Jack' },
{ name: 'Kate' }
]
var counter = 1;
$scope.$watchCollection('vm.filtered', function(){
console.log('Changed' + counter++);
})
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl as vm'>
<input type='text' ng-model='vm.filter' />
<ul>
<li ng-repeat='item in vm.filtered = (vm.items | filter : vm.filter)'>{{item}}</li>
</ul>
</div>

decoding the html tag from response and showing it in view

My below given response comes as encoded format , i am decoding it using a filter and displaying value in my html . But I need to display them as html in my view. So trustAsHtml has been used. but the problem here is when I use trustAsHtml my decoding doesn't occur.it shows exception unexpected token.
$scope.res= "data": [
{
"jd": "<p>this jd1</p>"
},
{
"jd": "<li>this jd2</li>"
},
{
"jd": "<ul>this jd3</ul>"
},
{
"jd": "<p>this jd4</p>"
}
]
}
JS:
$scope.trustAsHtml = $sce.trustAsHtml;
Filter:
app.filter('decodeFilter', function() {
return function(input) {
return decodeURIComponent(unescape(input));
};
});
Html:
<div ng-repeat="item in res">
<div ng-bind-html ="trustAsHtml(item.jd | decodeFilter)">
</div>
There seems to be issue with your ng-repeat object res, you should use res.data as per your code. I have made some correction from your custom filter as well. Also you can check this plunker for your given working example.
Template:
<div ng-repeat="item in res.data">
<div ng-bind-html ="item.jd | decodeFilter"></div>
</div>
Controller:
app.controller('MainCtrl', function($scope) {
$scope.res = {
"data": [ {
"jd": "<p>this jd1</p>"
}, {
"jd": "<li>this jd2</li>"
}, {
"jd": "<ul>this jd3</ul>"
}, {
"jd": "<p>this jd4</p>"
}]
};
});
app.filter('decodeFilter', function($sce) {
return function(input) {
return $sce.trustAsHtml(decodeURIComponent(input));
};
});
Note: The unescape() function was deprecated in JavaScript version 1.5. Use decodeURI() or decodeURIComponent() instead.
Which means unescape is equal to decodeURLComponent.
have you tried to enable it in the app.config with the $sceProvider like this?
angular
.module('myapp')
.config(["$locationProvider", "$sceProvider",function config($locationProvider, $sceProvider) {
$sceProvider.enabled(true);
$locationProvider.html5Mode(true);
});

Retrieve specific data within ng-repeat loop angularjs

I'd like to retrieve specific data within a JSON file within an ng-repeat loop, My code is as follows thus far, and it works correctly bringing in the correct low resolution url of the image. I want to display the first comment corresponding to this image from a specific user below it in the <p> tag, ie I want the the first "text" value always from the username "tellasaur". Not sure how to bring that in, could I have some help? thanks!
NG-REPEAT LOOP
<li ng-repeat="p in pics">
<img ng-src="{{p.images.low_resolution.url}}" />
<p></p>
</li>
CONTROLLER
app.controller('ShowImages', function($scope, InstagramAPI){
$scope.layout = 'grid';
$scope.data = {};
$scope.pics = [];
InstagramAPI.fetchPhotos(function(data){
$scope.pics = data;
console.log(data)
});
});
JSON
"images":{
"low_resolution":{
"url":"https:\/\/scontent.cdninstagram.com\/hphotos-xaf1\/t51.2885-15\/s320x320\/e15\/11243658_841091872640638_1858051687_n.jpg",
"width":320,
"height":320
},
},
"comments":{
"count":38,
"data":[
{
"created_time":"1436314585",
"text":"Living on a lake #amarie4107",
"from":{
"username":"tellasaur",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/11142181_1606991566225969_1204610350_a.jpg",
"id":"174270894",
"full_name":"kristella"
},
"id":"1024203434844916571"
},
{
"created_time":"1436317671",
"text":"Wow",
"from":{
"username":"sbcarol2002",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/10707061_359756607505353_826681437_a.jpg",
"id":"1280059782",
"full_name":"Susan Long"
},
"id":"1024229322726738700"
},
{
"created_time":"1436320519",
"text":"\ud83d\udc93 dreamyy",
"from":{
"username":"veekster",
"profile_picture":"https:\/\/igcdn-photos-h-a.akamaihd.net\/hphotos-ak-xtf1\/t51.2885-19\/11117059_1743047859255223_204225114_a.jpg",
"id":"31179150",
"full_name":"Victoria Wright"
},
"id":"1024253210688915485"
}
]
}
Here's one way to do it using a filter.
angular.module('app',[])
.filter('getFirstCommentFrom',function(){
return function(arr, user){
for(var i=0;i<arr.length;i++)
{
if(arr[i].from.username==user)
return arr[i].text;
}
return '';
}
})
.controller('TestCtrl', function($scope){
$scope.pics = [
{ "images":{
"low_resolution":{
"url":"https:\/\/scontent.cdninstagram.com\/hphotos-xaf1\/t51.2885-15\/s320x320\/e15\/11243658_841091872640638_1858051687_n.jpg",
"width":320,
"height":320
},
},
"comments":{
"count":38,
"data":[
{
"created_time":"1436314585",
"text":"Living on a lake #amarie4107",
"from":{
"username":"tellasaur",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/11142181_1606991566225969_1204610350_a.jpg",
"id":"174270894",
"full_name":"kristella"
},
"id":"1024203434844916571"
},
{
"created_time":"1436317671",
"text":"Wow",
"from":{
"username":"sbcarol2002",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/10707061_359756607505353_826681437_a.jpg",
"id":"1280059782",
"full_name":"Susan Long"
},
"id":"1024229322726738700"
},
{
"created_time":"1436320519",
"text":"\ud83d\udc93 dreamyy",
"from":{
"username":"veekster",
"profile_picture":"https:\/\/igcdn-photos-h-a.akamaihd.net\/hphotos-ak-xtf1\/t51.2885-19\/11117059_1743047859255223_204225114_a.jpg",
"id":"31179150",
"full_name":"Victoria Wright"
},
"id":"1024253210688915485"
}
]
}
}
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="TestCtrl">
<li ng-repeat="p in pics">
<img ng-src="{{p.images.low_resolution.url}}" />
{{p.comments.data|getFirstCommentFrom:'tellasaur'}}
<p></p>
</li>
</div>

"Conroller as" with ng-repeat with array of objects (does not work with 'this')

I noticed that for me this shows nothing in ng-repeat:
<ul ng-controller="UserCtrl as ctrl">
<li ng-repeat="user in ctrl.users">
{{user.name}}
</li>
</ul>
But this, works ok:
<ul ng-controller="UserCtrl">
<li ng-repeat="user in users">
{{user.name}}
</li>
</ul>
Why is that?
My Controller code is simple as that:
angular.module('main.controllers').controller('UserCtrl', ['$scope', 'UserResource', function UserCtrl($scope, UserResource) {
$scope.users = UserResource.list(); // works with $resource service
// ideally I would like type "var users = ..." without using $scope
var ctrl = this;
this.users = function() {
return UserResource.list();
};
return this;
}
where users are json array of objects I'm eventually getting as resolved promise result:
[
{ id: "1", name: "name1" },
{ id: "2", name: "name2" },
{ id: "3", name: "name3" }
]
Update:
The whole point is that it does not work with this.users and controller-as notation when it is wrapped in promise that I'm getting from $resource service.
return $resource(' /rest/user-api/user/:id/:action',
{id: "#id"}, //parameters default
{
list: { method: "GET", params: {action : "list"}, isArray: true},
});
In you controller you've got
this.users = function() ..
so in you view you need to execute that function to get users
<li ng-repeat="user in ctrl.users()">
this.users should be rather array like in my demo this.users2 and in that case you can use it in repeater as
<li ng-repeat="user in ctrl.users2">
var app = angular.module('app', []);
angular.module('app').service("userService", function($timeout, $q) {
this.getData = function() {
var deffered = $q.defer();
$timeout(function() {
var arr = [{
id: 1,
name: "Jack from Service"
}];
deffered.resolve(arr);
}, 2000);
return deffered.promise;
};
return this;
});
angular.module('app').controller('UserCtrl', ['userService',
function UserCtrl(userService) {
// ideally I would like type "var users = ..." without using $scope
var ctrl = this;
ctrl.users = function() {
return [{
id: 1,
name: "Jack Function"
}];
};
ctrl.users2 = [{
id: 1,
name: "Jack Array"
}];
////// users from service
this.usersFromService = [];
function activate() {
userService.getData().then(function(data) {
angular.copy(data, ctrl.usersFromService);
});
}
activate();
return this;
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<ul ng-controller="UserCtrl as ctrl">
<li ng-repeat="user in ctrl.users2">
{{user.name}}
</li>
<li ng-repeat="user in ctrl.usersFromService">
{{user.name}}
</li>
</ul>
</body>
My answer is that:
When I do this:
<ul ng-controller="UserCtrl as ctrl">
<li ng-repeat="user in ctr.users">
It does not work.
When I do this:
<ul ng-controller="UserCtrl as userCtrl">
<li ng-repeat="user in userCtrl.users">
or UserCtrl as a or UserCtrl as b ... - it works.
I just does not like ctrl as a name.
Thanks to all who were not voting "close". I can NOT explain how it differs from that I got as replies. In my case I use end-to end angular - NodeJS application that actually does whole client-server communication. Not sure it matters.
Maybe it clashes with another scopes.. I'm not sure yet. But the general advice - try to change the name after "as" and see what happen If you have issue like that. I know it's weird.

Angular JS filtering out used ids from a separate array

I've got an object of articles which contain all the articles on a site by id in an ng-repeat. I also have an array inside a products object of attached articles by id in a repeat.
Trying to only show the articles that are NOT attached already to the product. Not really sure how to iterate over the arrays and find matches and exclude them from the returned object.
https://gist.github.com/irthos/0565c66be0ab992adc0a
Is there a way I can ng-repeat="article in articles | (except for when any product.articles.$id === article.$id)"?
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.search = 1;
$scope.familes = [{
id:1,
name: "Kruders",
kids: [
{ name: "zoe" }
]
},
{
id:2,
name: "Halifax",
kids: [
{ name: "mike" } ,
{ name: "jim" }
]
},
{
id:3,
name: "Judes",
kids: [
]
}]
});
<html ng-app="app">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-controller="MainCtrl">
<input type="number" ng-model="search" />
<ul>
<li ng-repeat="family in familes | filter :{id:'!'+search}">id: {{family.id}} - Name:{{family.name}}</li>
</ul>
</body>
</html>
Please see that demo it should helps http://plnkr.co/edit/MNqBhOd1Y5GVezfa8zj0?p=preview
ng-repeat="article in articles | filter :{id:'!'+product.articles.$id})

Resources