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>
Related
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/
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);
};
}
]);
I am a novice with angular so bare with will I try and articulate what I am trying to achieve.
I have two web pages; a main 'login' page and a secondary 'about' page. The about page is nothing more than a page with HTML text. I access both pages simply with a link using ng-href.
I have a service which remembers some user login details which seem to persist when I click to the about page and then back to main.
However, I have no idea how to call a function when the user clicks back to the main page. This function would be the login function within the Main Controllers scope. I would then use the users details in the service to automatically login them in and display the users information.
This thread seems quite similar, but the user seems to be at a more advanced stage than me.
Main.html
<div class="main">
<div class="content" ng-hide="login">
<form>
... login fields ...
<button ng-click="$login()">Log in</button>
</form>
</div>
<div class="content" ng-show="login">
<form>
... user info ...
</form>
</div>
<div class="footer">
<a ng-href="#/about"/>About</a>
</div>
</div>
About.hml
<div class="about">
<div class="content">
... plain HTML ...
</div>
<div class="footer">
<a ng-href='#/main'/>mAIN</a>
</div>
</div>
app.js
'
use strict';
angular.module('sguAppApp', [
'ngResource',
'ngSanitize',
'ngRoute',
'ngAnimate'
])
.constant( 'eURL', '....webpage...' )
.config(function ($routeProvider) {
$routeProvider
.when('/main', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl'
})
.otherwise({
redirectTo: '/main'
});
});
main.js
angular.module('App')
.service('TestService', function() {
var TestService = {};
TestService.testVar1 = '';
TestService.testVar2 = '';
TestService.testVar3 = ''
return TestService;
})
.controller('MainCtrl', function ($scope, $rootScope, .... TestService) {
$scope.user = {};
$scope.user.logon = '';
$scope.user.password = '';
$scope.sData = '';
$scope.$login = function () {
$scope.loading = true;
... do stuff to testVarNs ...
}
}
.controller('AboutCtrl', function ($rootScope, $scope, TestService) {
... somehow call $login function in MainCtrl using the testVarNs in the service ...
(not sure if this is even needed)
})
The way you laid things out, either you are in the context of MainCtrl or AboutCtrl, when you navigate from one page to the other, the existing context gets destroyed and the destination one gets instanciated.
The login function should probably live in a service, this way you can call it from wherever you like.
In that way you shold inject your TestService in the controller and call the function in response to a click for example, with ng-click="TestService.$login()"
An alternative approach could be to have another controller that is in a context that wraps your MainCtrl or AboutCtrl, Say an AppCtrl that you define early in your html file, for example:
< body ng-controller="AppCtrl'>...
now, properties defined in the AppCtrl Context are visible inside the child contexts, so if you have a $login function defined there you can call it.
<nav>
<ul class="list">
<li ng-repeat="product in data | startFrom:currentPage*pageSize | limitTo:pageSize">
<span>{{product}}</span>
<a href="#getAttributes/{{product}}/{{code}}/{{name}}/{{hierName}}">
{{product.prd_name}}
</a>
</li>
</ul>
</nav>
I am calling the ng-route as above .
myApp.config([ '$routeProvider', function($routeProvider) {
$routeProvider
.when('/getAttributes/:product/:code/:name/:hierName', {
templateUrl : 'view/attributes.jsp',
controller : 'attributeController'
}).otherwise({
redirectTo : '/mainMenu'
});
} ]);
The Product is a JSON Object. The above code routes to otherwise if the product object contains "/" character. Any idea on how to resolve it.
First Approach: Use ng-click to Store the Model In A Service Then Go to Location
Start by adding an ng-click to your list item which calls get attributes on your controller taking caring to remove the href.
<nav>
<ul class="list">
<li ng-repeat="product in data | startFrom:currentPage*pageSize | limitTo:pageSize" ng-click="getAttributes(product)">
<span>{{product}}</span>
{{product.prd_name}}
</li>
</ul>
</nav>
Next, reconfigure your route to simply /getAttributes
myApp.config([
'$routeProvider', function($routeProvider) {
$routeProvider
.when('/getAttributes/', {
templateUrl: 'view/attributes.jsp',
controller: 'attributeController'
}).otherwise({
redirectTo: '/mainMenu'
});
}
]);
In your controller, add a method called getAttributes which will be invoked by the aforementioned ng-click. It will call a service and use its setModel function to persist which model was clicked. Finally, it will route getAttributes.
myApp.controller('someController', [
'$scope', '$location', 'someService', function($scope, $location, someService) {
$scope.getAttributes = function(model) {
someService.setModel(model);
$location.url('getAttributes');
};
}
]);
The attribute controller will call the same service and use its getModel method to set the model.
myApp.controller('attributeController', [
'$scope', 'someService', function($scope, someService) {
$scope.model = someService.getModel();
}
]);
The service would like something like the following:
myApp.service('someService', function() {
var model;
return {
getModel: function() {
return model;
},
setModel: function(newModel) {
model = newModel;
}
};
});
This approach is only suitable if you'll never be routing to getAttributes in any other way. A more flexible second approach is possible.
Second Approach: Use Resolve to Get the Model, Set In the Service Then Load in the Controller
Modify the href to be an ng-href and have it be getAttribute/123 or some such.
<nav>
<ul class="list">
<li ng-repeat="product in data | startFrom:currentPage*pageSize | limitTo:pageSize">
<span>{{product}}</span>
<a ng-href="/getAttributes/{{product.id}}">{{product.prd_name}}</a>
</li>
</ul>
</nav>
Modify your route to accept the product ID as seen below. Additionally, add a resolve object. This object will call someService which will in turn call your server, retrieve the products attributes and set the model variable equal to the result.
myApp.config([
'$routeProvider', function($routeProvider) {
$routeProvider
.when('/getAttributes/:id', {
templateUrl: 'view/attributes.jsp',
controller: 'attributeController',
resolve: {
getModel: function(someService) {
return someService.get();
}
}
}).otherwise({
redirectTo: '/mainMenu'
});
}
]);
As mentioned before, the service will take the passed ID on the /getAttributes/id route and use it to call the server. An alternative is to have the service call a repository for this instead. The end result is the same: set the model variable equal to the result of the call to the server.
myApp.service('someService', [
'$http', function($http) {
var model;
return {
get: function(id) {
return $http.get('api/attribute/' + id).then(function(response) {
model = response.data;
});
},
getModel: function() {
return model;
},
setModel: function(newModel) {
model = newModel;
}
};
}
]);
Finally, your attributeController will behave the same as the first example. It set $scope.model equal to someService.getModel() thereby providing the products attributes.
The advantage to this approach is that your route may deep linked from anywhere in your app without issue.
I have an angular CRUD app with a list of subjects. I can add, delete and edit the subjects. My problem is that when I add or delete a subject, the page does not refresh with the new list of subjects. I've tried including $route.reload(); but it gives me a console error:
ReferenceError: $route is not defined
Can anyone advise how to fix this error or a better way of refreshing the page?
HTML:
<h3>Add a Subject</h3>
<div ng-controller="SubjectNewCtrl">
<div class = "input-group">
<form name="newSubjectForm">
Name: <br /> <input type="text" name="name" ng-model="subjects.name">
<br />
<button type="button" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></button>
<a ng-click="createNewSubject()" class="btn btn-small btn-primary">Save Changes</a>
</form>
</div>
</div>
SubjectNewCtrl:
angular.module('myApp.controllers')
.controller('SubjectNewCtrl', ['$scope', 'SubjectsFactory', '$location',
function ($scope, SubjectsFactory, $location) {
// callback for ng-click 'createNewSubject':
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects);
$location.path('/subjects');
//This gives the console error
$route.reload();
}
$scope.subjects = SubjectsFactory.query();
}]);
EDIT- my routing in app.js
'use strict'
angular.module('myApp',
[
'ngRoute',
'ngResource',
'myApp.services',
'myApp.directives',
'myApp.controllers',
]);
angular.module('myApp')
.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/subjects', {templateUrl: 'partials/subjects/subject-list.html', controller: 'SubjectCtrl'}).
when('/subjects/new', {templateUrl: 'partials/subjects/subject-new.html', controller: 'SubjectNewCtrl'}).
when('/subjects/:subjectid', {templateUrl: 'partials/subjects/subject-detail.html', controller: 'SubjectEditCtrl'}).
otherwise({redirectTo: '/home'});
}]);
angular.module('myApp.controllers')
.controller('SubjectNewCtrl', ['$scope', 'SubjectsFactory', '$location', '$route',
function ($scope, SubjectsFactory, $location, $route) {
// callback for ng-click 'createNewSubject':
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects);
$location.path('/subjects');
//This gives the console error
$route.reload();
}
$scope.subjects = SubjectsFactory.query();
}]);
I add "$route" to your function
try to use location.reload();
example
vm.deleteUser = function (id) {
dataService.deletUser(id)
.then(function () {
location.reload();
});
};
use scope.$apply when updating the list of subjects do not force the whole page to reload...
$scope.createNewSubject = function() {
$scope.$apply(function() {
SubjectsFactory.create($scope.subjects);
});
};
btw. $location.path('/subjects') doesn't do anything if you are already on that page
You might want to try something like this instead of reloading the route:
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects).then(function (newSubject) {
$scope.subjects = SubjectsFactory.query(); // [1]
});
}
This version waits until the create request has completed before refetching the list of subjects (including the new subject), which will cause the view to refresh automatically.
In your code, you're reloading the current route/view immediately after initiating the create request without giving the create request a chance to complete, so the new subject actually doesn't exist yet.
[1] Alternatively, you might prefer to do $scope.subjects.push(newSubject) instead of refetching the list of subjects.