ng-repeat dynamic menu angularJS - angularjs

im trying to make a dynamic menu using ng-repeat, ui router and data from a json file.
this is my navbar.html
<ul class="nav navbar-nav" ng-controller="NavBarCtrl">
<div ng-repeat="item in navbarlist">
<li><a ui-sref="item.title" ui-sref-active="active">{{item.title}}</a></li>
</div> <!--ng-repeat-->
</ul>
navbar.js
var app = angular.module("catalogue", ['ui.router'])
app.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$stateProvider
.state('navbar', {
url: '/navbar',
templateUrl: 'navbar/navbar.html',
controller: 'NavBarCtrl'
})
}])
app.controller('NavBarCtrl', ['$scope', '$http', function($scope, $http, $stateParams) {
$http.get('navbar.json').then(function(response){
// $scope.navbar = response.data;
// $scope.navbar = "navbar.data" [];
// $scope.navbarlist = "navbarlist" [];
$scope.navbarlist = response.data;
});
}])
and navbar.json
{
"navbarlist": [
{
"title": "home"
},
{
"title": "category1"
},
{
"title": "category2"
},
{
"title": "category3"
},
{
"title": "category1"
},
{
"title": "category2"
}
]
}
and i have in index.html
<navbar></navbar>
but my nav bar does not show. Im assuming the problem is with the controller. Where have i gone wrong?

I think your problem not in controller.
You mentioned your tag in index.html, but there is no definition of it.
<navbar></navbar>
To using custom tags like this, read more about directives:
https://docs.angularjs.org/guide/directive
You need to make a directive and specify template or templateUrl indside of it.
For this code example, just put your mark up directly in index.html, it will solve the problem.
Your working code within directive on JSFiddle: https://jsfiddle.net/ukulikov/424z6o2x/

Related

How to load a new page and pass data from api?

I have page with list of teams. On click I need title and members of that team on another page. I just loaded teams in the list. Code is here:
angular.module('my-app').controller('MainController', function($scope, $http) {
$http.get("http://...").success(function(response) {
$scope.details = response;
});
});
and
<article ng-app="seed-angular">
<section ng-controller="MainController as mc">
<ul>
<li ng-repeat="x in details">
{{x.name}}
</li>
</ul>
</section>
</article>
As mentioned in the comments by Claies, you need to use a router in your app. From the docs:
Application routes in Angular are declared via the $routeProvider, which is the provider of the $route service. This service makes it easy to wire together controllers, view templates, and the current URL location in the browser. Using this feature, we can implement deep linking, which lets us utilize the browser's history (back and forward navigation) and bookmarks.
There are some libraries in which you can do that. I'll use ngRoute as an example as it comes with Angular.js.
To do so, you need to add the angular-route.js and load the ngRoute module:
var app = angular.module('seed-angular', [
'ngRoute'
]);
You also need to configure your $routeProvider to setup your URL routes, like this:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/team', {
templateUrl: 'team-list.html',
controller: 'MainController'
}).
when('/team/:teamId', {
templateUrl: 'team-detail.html',
controller: 'TeamDetailController'
}).
otherwise({
redirectTo: '/team'
});
}
]);
In the routes above, we've configured /team to route to a template page team-list.html. Note that the <a href=""> now passes a parameter teamId:
<article>
<section ng-controller="MainController">
<ul>
<li ng-repeat="x in details">
{{x.name}}
</li>
</ul>
</section>
</article>
We also configured /team/:teamId to route to a template page team-detail.html (note that :teamId means it's a parameter):
<article>
<section ng-controller="TeamDetailController">
Back
<div ng-repeat="x in details">
<strong>{{x._id}}</strong>
<ul>
<li>
{{x.firstName}} {{x.lastName}}
</li>
</ul>
</div>
</section>
</article>
In which you will be able to access teamId via $routeParams.teamId to retrieve the team details:
app.controller('TeamDetailController', function($scope, $http, $routeParams) {
var url = "http://est-teams.estudent.hr/api/teams/" + $routeParams.teamId + "/members";
$http.get(url).success(function(response) {
$scope.details = response;
});
});
See this fiddle for a working example.
if you want to pass the data you can create service and create function that store or set your data, then call it in your first controller that called the data and call it again in your next page controller here is the code :
this is the service :
myApp.service('sharedProperties', function() {
var stringValue = 'test string value';
var objectValue = {
data: 'test object value'
};
return {
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
},
getObject: function() {
return objectValue;
}
};
});
you can call it in your controller like this :
myController.controller('UserUpdateController', ['$scope', '$http','sharedProperties',
function($scope, $http, sharedProperties ) {
$scope.updateUser = function() {
.....
id = sharedProperties.getString();
};
}
]);
and set the data from your previous page like this :
myController.controller('UserListController', ['$scope', '$http','sharedProperties',
function($scope, $http, sharedProperties) {
$scope.updateUser = function(id){
console.log("from index "+id);
sharedProperties.setString(id);
};
}
]);

Trouble rendering view in Angular

I think what I'm trying to do is very simple, but somehow I am having trouble getting it to work. I'm sure there must be some simple solution, but I can't find it.
Basically, I have a simple array of dictionaries containing the resources I'm trying to render (defined as $scope.acts in the acts controller). I'm not importing JSON or anything like that, it's all right there in the controller file. The index is working fine, but I'm trying to render a 'show' view (not sure if this is the proper Angular terminology, I'm used to working with Rails, so I still think in those terms), for a single item in the array, and it isn't working. The template is loading, but it isn't fetching data from the array.
I really want to do this in the simplest manner possible, no bells or whistles. Eventually, I want to load the data from a Rails app, but I want to build this up one step at a time so that I get a feeling for how Angular is doing it's thing.
Here's my code.
app.js
var controllers, snowball_effect;
snowball_effect = angular.module('snowball_effect', [
'templates',
'ngRoute',
'ngResource',
'controllers'
]);
snowball_effect.config([
'$routeProvider', function($routeProvider) {
return $routeProvider
.when('/', {
templateUrl: "static_pages/index.html",
controller: 'StaticPagesController'
})
.when('/acts/index', {
templateUrl: "acts/index.html",
controller: 'ActsController'
})
.when('/acts/:id', {
templateUrl: "acts/show.html",
controller: 'ActsController'
});
}
]);
controllers = angular.module('controllers', []);
controllers.controller("StaticPagesController", ['$scope', {}]);
controllers.controller("NavBarController", [
'$scope',
'$routeParams',
'$location',
function($scope,$routeParams,$location) {
$scope.actsIndex = function() {
$location.path("/acts/index");
}
$scope.actsNew = function () {
$location.path("/acts/index");
}
}]);
ActsController.js
controllers = angular.module('controllers');
controllers.controller("ActsController", [
'$scope',
'$routeParams',
'$location',
'$resource',
function($scope,$routeParams,$location,$resource) {
$scope.acts = [
{
id: 1,
name: "Plant a Flower",
description: "Plant a flower in your garden or along the street.",
inspires: 1
}
];
$scope.addAct = function() {
$scope.acts.push($scope.newAct);
}
$scope.deleteAct = function(act) {
$scope.acts.splice($scope.acts.indexOf(act), 1);
}
$scope.linkToShowAct = function(act) {
$location.path('acts/' + act.id);
}
}]);
templates/acts/show.html
<div class="container" ng-controller="ActsController">
<div class="body">
<h1>
{{act.name}}
</h1>
<p class="act-show-description">
{{act.description}}
</p>
<p class="act-show-inspires">
<strong>Inspires:</strong>
{{act.inspires}}
</p>
Edit
Back
</div>
</div>
Your ActsController creates an array named acts, but your html does not reference an item in that array. It is using act instead of acts[0].
Try changing your html to this:
<div class="container" ng-controller="ActsController">
<div class="body">
<h1>
{{acts[0].name}}
</h1>
<p class="act-show-description">
{{acts[0].description}}
</p>
<p class="act-show-inspires">
<strong>Inspires:</strong>
{{acts[0].inspires}}
</p>
Edit
Back
</div>

How to load ui-router states into the content of ui-bootstrap tabs

I'm learning angular, and have been trying to dynamically load a HTML file fragment into the content pane of a tab.
In this linked plunker I have created an angular module to configure the states
var app = angular.module('Plunker', ['ui.router', 'ui.bootstrap'])
app.config([
'$stateProvider',
'$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state("tab1", { url: "/tab1", templateUrl: "tab1.html" })
.state("tab2", { url: "/tab2", templateUrl: "tab2.html" })
.state("tab3", { url: "/tab3", templateUrl: "tab3.html" });
$urlRouterProvider.otherwise('/');
}]);
app.controller("tabsController", function ($rootScope, $scope, $state) {
$scope.tabs = [
{ title: "My Tab 1", route: "tab1", active: true },
{ title: "My Tab 2", route: "tab2", active: false },
{ title: "My Tab 3", route: "tab3", active: false },
];
$scope.go = function (route) {
$state.go(route);
};
$scope.active = function (route) {
return $state.is(route);
};
$scope.$on("$stateChangeSuccess", function () {
$scope.tabs.forEach(function (tab) {
tab.active = $scope.active(tab.route);
});
});
});
and in the index.html body assign the ui-view a name to associate it with the state/route
<body ng-app="Plunker">
<div ng-controller="tabsController">
<uib-tabset>
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disable="tab.disabled">
<div ui-view="{{tab.route}}"></div>
</uib-tab>
</uib-tabset>
</div>
</body>
Each tab should have content coming from the respective html file fragment tab1.html, tab2.html or tab1.html. But I cant get it to work. Any help making this work would be much appreciated.
You want to have one partial for each tab. For that, the named views feature of ui-router can help you. You won't change state, but having the content on dedicated views allows you to keep the parent template light and nicely organize your code. Moreover you could reuse the tab templates elsewhere.
State definition where the tabset component resides:
$stateProvider
.state('example', {
url: '/example',
views: {
"tab1": { templateUrl: "tab1.html" },
"tab2": { templateUrl: "tab2.html" },
"tab3": { templateUrl: "tab3.html" },
}
Tabset definition:
<uib-tabset>
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" ...>
<div ui-view="{{tab.route}}"></div> <!-- ex: <div ui-view="tab1"></div> -->
</uib-tab>
</uib-tabset>
See updated plunker

AngularJS - Dynamic Default nested views from Json Data not appearing

1. Html:
<html>
<head><title>MyApp</title></head>
<body data-ng-app="app">
<ul><li><a data-ui-sref="home" style="cursor:pointer;">Home</a></li></ul>
<div data-ui-view="header"></div>
<div data-ui-view="container"></div>
<div data-ui-view="footer"></div>
<script src="/Scripts/angular-1.2.9/angular.min.js"></script>
<script src="/Scripts/angular-1.2.9/animate/angular-animate.js"></script>
<script src="/Scripts/angular-1.2.9/ui-router/angular-ui-router.js"></script>
<script src="/Scripts/angular-1.2.9/ui-bootstrap/ui-bootstrap-custom-tpls-0.11.0.js"></script>
<script src="/_temp/app/app.js"></script>
</body>
</html>
2. App.js:
'use strict';
var $stateProviderRef = null;
var $urlRouterProviderRef = null;
var app = angular.module('app', ['ui.router']);
app.factory('menuItems', function ($http) {
return {
all: function () {
return $http({
url: '/_temp/app/jsonData/statesJson.js',
method: 'GET'
});
}
};
});
app.config(function($locationProvider, $urlRouterProvider, $stateProvider) {
$urlRouterProviderRef = $urlRouterProvider;
$stateProviderRef = $stateProvider;
$locationProvider.html5Mode(false);
$urlRouterProviderRef.otherwise("/");
});
app.run(['$q', '$rootScope', '$state', 'menuItems',
function ($q, $rootScope, $state', menuItems) {
menuItems.all().success(function (data) {
angular.forEach(data, function (value, key) {
$stateProviderRef.state(value.name, value);
});
**$state.go("home"); <--- SOLUTION**
});
}]);
3. Data:
[
{
"name": "root",
"url": "/",
"parent": "",
"abstract": true,
"views": {
"header": { "template": "header.html" },
"footer": { "template": "footer.html" }
}
},
{
"name": "home",
"url": "/home",
"parent": "root",
"views": {
"container#": { "template": "home page" }
}
}
]
PROBLEM:
The nested views were suppose to show up on load not the click event. I tried to play with the $urlRouterProviderRef.otherwise("/") to no avail.
What must I correct to have the 3 nested views appear on load not a click event.
Thanks.
UPDATE:
I made a Plunker to help show the problem PLUNKER LINK
Radim Köhler
Sweet!! I updated my plunker to reflect multiple states if anyone wants to see for ideas.
The issue here is: timing. The $urlRouterProviderRef.otherwise("/") instruction is used/executed too soon, before the $http.get() returns the state definition, i.e. before states are defined in foreach: $stateProviderRef.state(value.name, value);
If this would preceed the otherwise trigger, it would work (as you experienced for example with local variable, which is available soon enough).
But we can use another feature: $state.go (older doc link, but like it more than new)
So, with this "dynamic" state definition and $state.go ... we can achieve the desired
app.run(['$q', '$rootScope', '$state', 'menuItems',
function ($q, $rootScope, $state, menuItems) {
menuItems
.all()
.success(function (data)
{
angular.forEach(data, function (value, key) {
$stateProviderRef.state(value.name, value);
});
$state.go("home")
});
}]);
See working plunker.
NOTE: the above const "home" could be just anohter part of the passed JSON definition... e.g. instead of [] use an object with default : "home" and states : [...]. Because do not send array anyway. See Anatomy of a Subtle JSON Vulnerability, cite:
One common mitigation is to make sure that your JSON service always returns its response as a non-array JSON object.

Creating a JSFiddle with Angular-ui-router and multiple views

I have a question I would like to ask the community, but am having trouble setting up the required JSFiddle to make it easier to demonstrate the issue. I want to create a fiddle with three views side by side using Angular's ui-router. Seems simple, but for some reason I can't get the views' controller's to initialize. The main app loads, as evidenced by console messages, but I'm stumped.
The Fiddle is here, and for completeness sake, the html and js are here:
HTML:
<div ui-view="top" class="top">
<br />
$scope.testmsg = {{testmsg}}
<br />
$scope.statename = {{statename}}
<br />
top!
</div>
<div ui-view="middle" class="middle">middle!</div>
<div ui-view="bottom" class="bottom">bottom!</div>
JS:
/* myApp module */
var myApp = angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function ($stateProvider) {
$stateProvider.state('home', {
url: "/",
views: {
'top': {
url: "",
template: '<div>top! {{topmsg}}</div>',
controller: function ($scope) {
$scope.topmsg = "loaded top!";
console.log("top ctrl!"); // this does NOT show in console
}
},
'middle': {
url: "",
template: '<div>middle! {{middlemsg}}</div>',
controller: function ($scope) {
$scope.middlemsg = "loaded middle!";
console.log("middle ctrl!"); // this does NOT show in console
}
},
'bottom': {
url: "",
templateUrl: '<div>bottom! {{bottommsg}}</div>',
controller: function ($scope) {
$scope.bottommsg = "loaded bottom!";
console.log("bottom ctrl!"); // this does NOT show in console
}
}
},
onEnter: function () {
console.log("entered home state"); // this does NOT show in console
}
});
}])
.controller('MyAppCtrl', function ($scope, $state/*, $stateParams*/) {
$scope.statename = $state.current.name;
$scope.testmsg = "app scope working!";
console.log("MyAppCtrl initialized!"); // this shows in console
$state.go("home");
});
My body tag has the correct (I believe) references to my app and controller: <body ng-app="myApp" ng-controller="MyAppCtrl"></body>... I'm stuck. Any help would be great.
Thanks in advance!
I think your only mistake is in the configuration for the 'bottom' view. You have templateUrl instead of template. After I made this change in your fiddle, all the controllers initialize correctly.
Here's an updated fiddle. But like I said, changing templateUrl to template is the only change. Hope this helps!

Resources