I am new in angular js, I am trying to format a json data with angular js.
Here is my json data
[
{"field_add_link": "Home"},
{"field_add_link": "About Us"}
]
here is my conroller
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController',function($scope, $http) {
$http.get('http://localhost/drupal3/menu')
.then(function(response) {
$scope.links = response;
});
});
and finally here is how i am fetching the json data with angular
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links" ng-bind-html="links">
<p>{{ link.field_add_link }}</p>
</div>
</div>
no output was shown after this, giving an error Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context. in the browser's console
but when I used ng-bind-html="links[0].field_add_link instead of ng-bind-html="links" and <p>{{ link[0].field_add_link }}</p> instead of <p>{{ link.field_add_link }}</p>
then i get Home as output 'without interpreting the tag'
Pls, how do I go about this?
First of all you dont need the ng-bind-html attribute on your div with ng-repeat. It should be on your p tag. Second, you need to bind link (the current element of the ng-repeat-loop) not links (the array). Although you need to look into the error [$sce:unsafe]. HTMl can only be bind to an element-body if it is trusted. For that you need to have, for example, a filter.
myApp.filter ('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml (text);
};
}]);
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link | to_trusted"></p>
</div>
</div>
You just need to move your ng-bind-html from div to <p> like following code.
<p ng-bind-html="link.field_add_link"></p>
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController', function($scope, $http) {
var data = [{"field_add_link": "Home"},
{"field_add_link": "About Us"}];
$scope.links = data;
//For demo, removed the http call
});
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-sanitize.js"></script>
</head>
<body ng-app="myApp">
<div class="col-md-8 content" ng-controller="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link"></p>
</div>
</div>
</body>
Related
I'm trying to setup a nested repeat in angular using an associative array of arrays. For example I have a structure as such:
collections['key1'] = [obj1,obj2,obj3,obj4];
collections['key2'] = [obj5,obj6,obj7];
I want to have a view with a structure of:
<div ng-repeat="collection in collections">
<h4>{{collection.id}}</h4>
<div ng-repeat="item in collection">
<span>{{item.name | item.value}}</span>
</div>
</div>
However as soon as I add in ng-repeat="collection in collections" my view becomes blank. Is there a way to do this in angular or will I need to update the way i'm storing my data if I want to loop it in such a way? Thanks.
Just to give you an example how to use it
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.school = {
classes:[
{name:"Class 1", peoples:["Peter","Sue","Marc"]},
{name:"Class 2", peoples:["John","Edward","Sara"]}
]
}
});
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="class in school.classes">
<h4>{{class.name}}</h4>
<div ng-repeat="person in class.peoples">
<label>{{person}}</label>
</div>
<br>
</div>
</div>
</body>
</html>
I had a hard issue figuring out on how to hide and show icon/text with angular code. I am completely new to angular and tried hard on the below fiddle code. How do I hide + or minus icon with .closest in such dom scenarios.
<div ng-controller="MyCtrl">
{{name}}
<div data-toggle="collapse" aria-expanded="true" data-target="#list-item-line-0" id="expandCollapseChild" ng-click="addExpandCollapseChildIcon()">
<div>
<div>
<label>
<div>
<span class="icon-expand">-</span>
<span class="icon-collapse">+</span>
</div>
<div>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.addExpandCollapseChildIcon = function() {
alert('');
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'none');
} else {
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'block');
}
}
}
In Angular, this is the wrong approach. You shouldn't actually show or hide elements inside the controller. That's applying a jQuery style (working directly on the DOM) to Angular.
In Angular, you'd use something like ng-if, ng-show or ng-class, all of which can link back to a property on the scope object that is accessible via the controller.
Here are some examples:
<div ng-if="myProp === 'ShowMe'">
<div ng-show="myProp === 'ShowMe'">
<div ng-class="{myCssClass: myProp === 'ShowMe'">
Inside your controller, you'd have something like this:
function MyCtrl($scope) {
$scope.myProp = 'ShowMe';
$scope.addExpandCollapseChildIcon = function(newPropValue) {
$scope.myProp = newPropValue;
}
}
Here's some links to documentation on ng-if, ng-show and ng-class:
https://docs.angularjs.org/api/ng/directive/ngIf
https://docs.angularjs.org/api/ng/directive/ngShow
https://docs.angularjs.org/api/ng/directive/ngClass
AngularJS has a bunch of angulary ways of doing things, your question for example might look like this:
var app = angular.module("app", []);
app.controller("ctrl", function($scope) {
$scope.collapsed = true;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
<span ng-bind="collapsed ? '+' : '-'"></span>
</div>
</div>
It watches a model and changes it's appearance based on that model using the ternary operator within ng-bind.
The way you defined your app and controller was incorrect. There's a bunch of different ways to do this as you can see from the answers.
I took this approach:
<div ng-app='myApp' ng-controller="MyCtrl">
{{name}}
<div>
<div>
<div>
<label>
<div>
<span ng-show='(collapsed != false)' class="icon-expand">-</span>
<span ng-show='(collapsed == false)' class="icon-collapse">+</span>
</div>
<div ng-click='collapsed = !collapsed'>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.name = 'Superhero';
$scope.collapsed = false;
});
</script>
Create a scoped variable that indicated whether or not it is collapsed . Then change that variable and the ng-shows will react.
As per the AngularJS article (have a look in nested controller fragment), I'm trying to implement nested controllers with ng-include
index.html
<body id="spaWrapperApp" ng-app="spaWrapperApp">
<div class="container-fluid" id="wrapper" ng-controller="mainController">
<div class="navigation">
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f1.html')">
<span>Page 1</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f2.html')">
<span>Page 2</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f3.html')">
<span>Page 3</span>
</a>
</div>
<div id="content" >
<div ng-include="currentPage"></div>
</div>
</div>
<script type="text/javascript">
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
console.log($scope);
$scope.requestPage = function(friendlyURL){
console.log(friendlyURL);
$scope.currentPage = friendlyURL;
}
}]);
</script>
</body>
Page1 (code given below)file will injected in ng-include
<div>Testing page include 1</div>
<hr/>
<br/>
<div ng-controller="FirstController">
<p>1# {{ name }}</p>
<div ng-controller="SecondController">
<p>2# {{ name }}</p>
</div>
</div>
<script type="text/javascript">
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
</script>
In the whole case the end result will be nested controller injected in ng-include area.
The issue is when I run that code that time this error is shown to me.
"Error: [ng:areq] Argument 'FirstController' is not a function, got undefined"
Any idea what exactly going wrong ?
Something unexpected going in AngularJS.
If you are using ng-include and try to inject pageX in that area and pageX contains some script, in that case pageX script not executed, for that I just write all the angularJS controllers handler in index.html only and it works fine for me.
like
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
$scope.requestPage = function(friendlyURL){
$scope.currentPage = friendlyURL;
}
}]);
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
I am building a quick Angular app that uses a service to grab a JSON from a URL.
The JSON structure looks like this:
{news:[{title:"title",description:'decription'},
{title:"title",description:'decription'},
{title:"title",description:'decription'}
]};
What I need is just the array within the news object.
My code to import the JSON is as follows:
app.factory('getNews', ['$http', function($http) {
return $http.get('URL')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
Then to add the data to the $scope object in the controller I do this:
app.controller('MainController', ['$scope','getNews', function($scope, getNews) {
getNews.success(function(data)) {
$scope.newsInfo = data.news;
});
});
But it doesn't work. When I load the html page, there is only white. My thinking is that this is because it isn't grabbing the array within the JSON and using that data to populate the HTML directive I set up.
newsInfo.js:
app.directive('newsInfo',function(){
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl:'newsInfo.html'
};
});
newsInfo.html:
<h2>{{ info.title }}</h2>
<p>{{ info.published }}</p>
My HTML doc is:
<head>
<title></title>
<!--src for AngularJS library-->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
</head>
<body ng-app="THE APP NAME"> <!--insert ng app here-->
<div ng-controller="MainController"> <!--insert ng controller here-->
<div ng-repeat="news in newsInfo"><!--insert ng repeat here-->
<!-- directive goes here-->
<newsInfo info="news"></newsInfo>
</div>
</div>
<!-- Modules -->
<script src="app.js"></script>
<!-- Controllers -->
<script src="MainController.js"></script>
<!-- Services -->
<script src="getNews.js"></script>
<!-- Directives -->
<script src="newsInfo.js"></script>
</body>
Thoughts?
Change
<newsInfo info="news"></newsInfo>
to
<news-info info="news"></news-info>
example: https://jsfiddle.net/bhv0zvhw/3/
You haven't specified the controller.
<div ng-controller="MainController"> <!--insert ng controller here-->
<div ng-repeat="news in newsInfo"><!--insert ng repeat here-->
<!-- directive goes here-->
<newsInfo info="news"></newsInfo>
</div>
</div>
$scope.getNews = function(){
return $http.get('URL').success(function(data) {
return data.news;
})
};
^ This, just change it so that the success function returns only the news!
While I am answering my own question, I should point out that everyone's answers were also correct. The code had multiple errors, but the final error was fixed by doing the following:
Apparently I had to upload the newsInfo.html doc to an S3 bucket and use that URL as “Cross origin requests are only supported for HTTP.” But then Angular blocked that external source with the Error: "$sce:insecurl Processing of a Resource from Untrusted Source Blocked".
So since the html template was so simple, i just bipassed this issue by typing in the template directly into the .js directive and it worked! thanks everyone for the help!
I'm using AngularJs to read the iTunes API. I want to get all the results in <entry> but so far I only get the first result:
<div class="container" ng-controller="appController">
<div class="item" ng-repeat="chart in charts">
<h2>{{chart.entry[$index]['im:name'].label}}</h2>
</div>
The result is im:name from entry[0]; when I replace $index with a number then I get the result as well, so clearly everything is loaded just fine.
Controller:
app.controller('appController', ['$scope', 'charts', function($scope, charts) {
charts.success(function(data) {
$scope.charts = data;
});
}]);
Loading JSON file:
app.factory('charts', ['$http', function($http) {
return $http.get('https://itunes.apple.com/us/rss/topsongs/limit=100/json')
.success(function(data) {
return data;
})
.error(function(data) {
return data;
});
}]);
I think you want to repeat over charts.feed.entry instead.
<div class="item" ng-repeat="entry in charts.feed.entry">
<h2>{{entry['im:name'].label}}</h2>
</div>
Edit: An explanation as to why this is charts.feed.entry and not charts.entry. From the question:
<div class="item" ng-repeat="chart in charts">
This looped through charts, which because it was an object and not an array, meant looping through its properties. There was only one, so there was one iteration, which assigned the single property, feed, to chart. Therefore:
chart.entry[$index]['im:name'].label
was equivalent to:
charts.feed.entry[$index]['im:name'].label
Based on your JSON structure, you're trying to loop over charts but it's not an array, it's just an object with an array called entry that has all the entries. So you should change your
<div class="item" ng-repeat="chart in charts">
<h2>{{chart.entry[$index]['im:name'].label}}</h2>
</div>
to
<div class="item" ng-repeat="entry in charts.feed.entry">
<h2>{{entry ['im:name'].label}}</h2>
</div>
Try changing it to
<div class="container" ng-controller="appController">
<div class="item" ng-repeat="chart in charts">
<div class="item" ng-repeat="entry in chart.entry">
<h2>{{entry['im:name'].label}}</h2>
</div>
</div>