I am starting out on the angular seed. I have a json file that displays items like the below.
{
"id":"1",
"name":"Spain",
"abbrev":"esp"
}
When I click on a country in the list I want to the display the details such as the name for this item.
I have this working as shown below.
/* app.js */
'use strict';
// Declare app level module which depends on views, and components
angular.module('myApp', ['ngRoute','myApp.controllers','myApp.services'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'templates/view1.html',
controller: 'CountryCtrl'
});
}])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/:name', {
templateUrl: 'templates/view2.html',
controller: 'CountryCtrl'
});
}])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.otherwise({redirectTo: '/'});
}]);
/* services.js */
angular.module('myApp.services', [])
.factory('Countries', ['$http', function($http) {
var Countries = {};
Countries.name = '';
Countries.listCountries = function () {
return $http.get('../api/countries');
},
Countries.ChangeName = function (value) {
Countries.name = value;
}
return Countries;
}]);
/* controllers.js */
angular.module('myApp.controllers', [])
.controller('CountryCtrl', ['$scope', 'Countries', '$location', function($scope, Countries,$location) {
listCountries();
function listCountries() {Countries.listCountries()
.success(function (data, status, headers, config) {
$scope.countries = data.countries;
})
.error(function(data, status, headers, config) {
$scope.status = 'Unable to load data: ' + error.message;
});
}
$scope.name = Countries.name;
$scope.changeView = function(countryName,indx){
$location.path(countryName);
$scope.name = Countries.ChangeName(countryName);
}
}]);
/* templates/view1.html */
<ul>
<li ng-repeat="country in countries">
<div ng-click="changeView(country.name,$index)">{{country.name}}</div>
</li>
</ul>
/* templates/view2.html */
{{name}}
What I can't get to work is that if I go to http://www.example.com/app/#/ then navigate to spain in the list then I get taken to http://www.example.com/app/#/esp and {{name}} gets outputted as esp.
However if I navigate straight to http://www.example.com/app/#/esp without first clicking on spain in the list I get no value in my $scope.name
How can I achieve this?
I want the name to also be set based on the location path if it is available.
I know that $location.$$path will get me /esp however I don't really think this is the best idea to use this incase the url builds out to something bigger eg http://www.example.com/app/#/esp/events
can I some how access the index or id of the item so that I can then access the data like
{{countries[0].name}}
where 0 is id of esp - 1.
What is the best approach?
Mate, there are a couple of issues with your app.
Your service retains "state" although is only used to retrieve information
You're using the same controller to 2 different views (bad practice)
$scope.status = 'Unable to load data: ' + error.message; --> Error is not defined
There are a couple of js errors too, like strayed commas and stuff
Anyways, here's a revised version of your code. Fiddle
// Instantiate your main module
var myApp = angular.module('myApp', ['ngRoute']);
// Router config
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'templates/view1.html',
controller: 'CountryListCtrl'
})
.when('/:id', {
templateUrl: 'templates/view2.html',
controller: 'CountryCtrl'
})
}
]);
// Your Factory. Now returns a promise of the data.
myApp.factory('Countries', ['$q',
function($q) {
var countriesList = [];
// perform the ajax call (this is a mock)
var getCountriesList = function() {
// Mock return json
var contriesListMock = [{
"id": "0",
"name": "Portugal",
"abbrev": "pt"
}, {
"id": "1",
"name": "Spain",
"abbrev": "esp"
}, {
"id": "2",
"name": "Andora",
"abbrev": "an"
}];
var deferred = $q.defer();
if (countriesList.length == 0) {
setTimeout(function() {
deferred.resolve(contriesListMock, 200, '');
countriesList = contriesListMock;
}, 1000);
} else {
deferred.resolve(countriesList, 200, '');
}
return deferred.promise;
}
var getCountry = function(id) {
var deferred = $q.defer();
if (countriesList.length == 0) {
getCountriesList().then(
function() {
deferred.resolve(countriesList[id], 200, '');
},
function() {
deferred.reject('failed to load countries', 400, '');
}
);
} else {
deferred.resolve(countriesList[id], 200, '');
}
return deferred.promise;
}
return {
getList: getCountriesList,
getCountry: getCountry
};
}
]);
//Controller of home page (pretty straightforward)
myApp.controller('CountryListCtrl', ['$scope', 'Countries',
function($scope, Countries) {
$scope.title = 'Countries List';
$scope.countries = [];
$scope.status = '';
Countries.getList().then(
function(data, status, headers) { //success
$scope.countries = data;
},
function(data, status, headers) { //error
$scope.status = 'Unable to load data:';
}
);
}
]);
// controller of Country page
// Notice how we use $routeParams to grab the "id" of our country from the URL
// And use our service to look for the actual country by its ID.
myApp.controller('CountryCtrl', ['$scope', '$routeParams', 'Countries',
function($scope, $routeParams, Countries) {
$scope.country = {
id: '',
name: '',
abbrev: ''
};
var id = $routeParams.id;
Countries.getCountry(id).then(
function(data, status, hd) {
console.log(data);
$scope.country = data;
},
function(data, status, hd) {
console.log(data);
}
);
}
]);
In your "CountryCtrl", if you include $routeParams and use $routeParams.tlaname, you will have access to the tlaname. You can then use that to initialize your data.
Related
I am trying to route my page to another page once the controller is accessed but its not working. I can route the first two pages but the third one is not working. Can someone help me on this.
This is my routing code:
$routeProvider', function ($routeProvider) {
$routeProvider.
when('/category', {
//templateUrl : 'js/partials/course-list.html',
controller : 'CategoryController'
}).
when('/category/:categoryid', {
templateUrl : 'js/partials/film-list.html',
controller : 'MovieController'
}).
when('/actor/:filmid', {
templateUrl : 'js/partials/actor-list.html',
controller : 'ActorController'
}).
otherwise({
redirectTo : '/'
});
}
Currently my ActorController is not working. Once i click on the movies it should show the actor of the films but in my case its not working
This is my partial html file for the movie-list.html
<section>
<h3>{{movieCount}}</h3>
<table>
<tr data-ng-repeat="movie in movies" data-ng-click="selectFilm($event,movie)" style="cursor: pointer;">
<td>{{movie.title}}</td>
</tr>
<strong>{{successMessage}}</strong>
</table>
And this is my controller code
).controller('ActorController',
[
'$scope',
'dataService',
'$routeParams',
function ($scope, dataService, $routeParams){
$scope.actors = [ ];
$scope.actorCount = 0;
var getActors = function (moviecode) {
dataService.getActors(moviecode).then(
function (response) {
$scope.actorCount = response.rowCount + ' actors';
$scope.actors = response.data;
$scope.showSuccessMessage = true;
$scope.successMessage = "Actor Success";
},
function (err){
$scope.status = 'Unable to load data ' + err;
}
); // end of getStudents().then
};
// only if there has been a courseid passed in do we bother trying to get the students
if ($routeParams && $routeParams.filmid) {
console.log($routeParams.filmid);
getActors($routeParams.filmid);
}
}
]
)
This is the selectFilm() code from the MovieController
$scope.selectedFilm = {};
$scope.selectFilm = function ($event,movie) {
$scope.selectedFilm = movie;
$location.path('/actor/' + movie.film_id);
}
This is the movie controller code
).controller('MovieController',
[
'$scope',
'dataService',
'$routeParams',
'$location',
function ($scope, dataService, $routeParams, $location){
$scope.movies = [ ];
$scope.movieCount = 0;
var getMovies = function (moviecode) {
dataService.getMovies(moviecode).then(
function (response) {
$scope.movieCount = response.rowCount + ' movies';
$scope.movies = response.data;
$scope.showSuccessMessage = true;
$scope.successMessage = "Movies Success";
},
function (err){
$scope.status = 'Unable to load data ' + err;
}
); // end of getStudents().then
};
$scope.selectedFilm = {};
$scope.selectFilm = function ($event,movie) {
$scope.selectedFilm = movie;
$location.path('/actor/' + movie.film_id);
// $window.location.href = '/actor/' + movie.film_id
console.log(movie.film_id);
}
// only if there has been a courseid passed in do we bother trying to get the students
if ($routeParams && $routeParams.categoryid) {
console.log($routeParams.categoryid);
getMovies($routeParams.categoryid);
}
}
]
)
I solved the problem by myself wher first of all the $location variable was not defined in the function and later on the movie object dont have the film_id so I had to readjust my SQL query to make it work. After changing the SQL query i can route my page now.
I can't figure out how to destroy my cache to get a new list from my server.
When I get the first list, it's work perfect, but after inserting informations to my database and sending another get to my server, the browser only show the cached version of my list, without the new data.
I tried to use cacheFactory like this:
$cacheFactory.get('$http').removeAll();
but it doesn't worked.
Here is my angular Module, Service and Controller.
Module myApp
var app = angular.module('myApp', ['ngRoute', 'LocalStorageModule', 'angular-loading-bar', 'smart-table']);
app.config(function ($routeProvider) {
$routeProvider.when("/home", {
controller: "homeController",
templateUrl: "/web/views/home.html"
});
$routeProvider.when("/cidades", {
controller: "cidadesController",
templateUrl: "/web/views/basico/cidades/cidades.html"
});
$routeProvider.otherwise({ redirectTo: "/home" });
});
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptorService');
});
app.run(['authService', function (authService) {
authService.fillAuthData();
}]);
cidadesService
'use strict';
app.factory('cidadesService', ['$http', '$cacheFactory', function ($http, $cacheFactory) {
var serviceBase = 'http://localhost:22207/';
var serviceFactory = {};
var _getCidades = function () {
$cacheFactory.get('$http').removeAll(); //This doesn't worked
return $http.get(serviceBase + 'api/cidades/getall').then(function (results) {
return results;
});
};
serviceFactory.getCidades = _getCidades;
return serviceFactory;
}]);
cidadesController
'use strict';
app.controller('cidadesController', ['$scope', 'cidadesService', function ($scope, service) {
$scope.cidade = {
id: "",
nome:"",
};
$scope.message = "";
$scope.getCidades = function () {
service.getCidades().then(function (results) {
$scope.cidades = [];
$scope.collection = [];
$scope.cidades = results.data;
$scope.collection = [].concat($scope.cidades);
}, function (err) {
$scope.message = err.error_description;
});
};
//Initializing the list
$scope.getCidades();
}]);
I really don't see anything wrong, but in any case you can add unique param for your request to prevent caching
like
$http.get(serviceBase + 'api/cidades/getall?unique=' + new Date().getTime())
This may be very basic but I'm new to angular and am stumped. I have 2 views that need to access the same user input data from a form. Each view has it's own controller.
Here's where I'm at:
JAVASCRIPT
.config(function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl : 'view1.html',
controller: 'ctrl1'
})
.when('/view2', {
templateUrl : 'view2.html',
controller : 'ctrl2'
})
})
//SERVICE TO HOLD DATA
.service('Data', function() {
return {};
})
//CONTROLLER 1
.controller('ctrl1', ['$scope', 'Data', function($scope, Data) {
$scope.data = Data;
var $scope.initValue = function() {
$scope.data.inputA = 0; //number
$scope.data.inputB = 0; //number
}
var $scope.onSubmit = function() {
$scope.data.result = $scope.data.inputA + $scope.data.inputB;
}
}])
//CONTROLLER 2
.controller('ctrl2', ['$scope', 'Data', function($scope, Data) {
$scope.data = Data;
}
}])
HTML (view2.html)
<p>Result is {{data.result}}</p>
This displays nothing, I'm thinking it's because the service or controller resets the values when changing views? Am I just totally wrong for using a service to do this?
You have to update the data in the service so that it can be used in another controller:
// define a var container in the service
// you can make it neat by creatin a getter and setter
.service('Data', function() {
var value = null;
var setValue = function(val) {
this.value = val;
};
var getValue = function() {
return this.value;
};
return {
value: value,
setValue: setValue,
getValue: getValue,
};
}
Then in controller 1 you can set the value in the service like so:
//CONTROLLER 1
.controller('ctrl1', ['$scope', 'Data', function($scope, Data) {
$scope.inputA = 0;
$scope.inputB = 0;
$scope.onSubmit = function() {
$scope.result = $scope.inputA + $scope.inputB;
Data.setValue($scope.result);
}
}])
And in controller 2 you can use the value like so:
//CONTROLLER 2
.controller('ctrl2', ['$scope', 'Data', function($scope, Data) {
$scope.value = Data.getValue();
}])
Hope this will help.
Lets say i list all users in a list, when i click a user i want to route to a new view and get the data for the selected person.
What is the preferred way? Should i move the data i already got when i listed the users or should i create a new server call?
My first thought is to pass the data, but the problem with this is that the data the gets lost if the user refreshes the page.
What is the best practice to solve this?
Small example:
(function() {
var app = angular.module('app');
var controllerId = 'app.controllers.views.userList';
app.controller(controllerId, [
'$scope', 'UserService',function ($scope, userService) {
var vm = this;
vm.users = [];
userService.getAllUsers().success(function (data) {
vm.users= data.users;
});
var gotoUser = function(user) {
// Pass the user to UserDetail view.
}
}
]);
})();
<div data-ng-repeat="user in vm.users" ng-click="vm.gotoUser(user)">
<span>{{customer.firstname}} {{customer.lastname}}</span>
</div>
i now list the user details in UserDetail view, this view is now vulnerable against a browser refresh.
Typically most people just create a new server call, but I'll assume you're worried about performance. In this case you could create a service that provides the data and caches it in local storage.
On controller load, the controller can fetch the data from the service given the route params and then load the content. This will achieve both the effect of working on page refresh, and not needing an extra network request
Here's a simple example from one of my apps, error handling left out for simplicity, so use with caution
angular.
module('alienstreamApp')
.service('api', ['$http', '$q','$window', function($http, $q, $window) {
//meta data request functions
this.trending = function() {
}
this.request = function(url,params) {
var differed = $q.defer();
var storage = $window.localStorage;
var value = JSON.parse(storage.getItem(url+params))
if(value) {
differed.resolve(value);
} else {
$http.get("http://api.alienstream.com/"+url+"/?"+params)
.success(function(result){
differed.resolve(result);
storage.setItem(url+params,JSON.stringify(result))
})
}
return differed.promise;
}
}]);
I would say that you should start off simple and do a new server call when you hit the new route. My experience is that this simplifies development and you can put your effort on optimizing performance (or user experience...) where you will need it the most.
Something like this:
angular.module('app', ['ngRoute', 'ngResource'])
.factory('Users', function ($resource) {
return $resource('/api/Users/:userid', { userid: '#id' }, {
query: { method: 'GET', params: { userid: '' }, isArray: true }
});
});
.controller("UsersController",
['$scope', 'Users',
function ($scope, Users) {
$scope.loading = true;
$scope.users = Users.query(function () {
$scope.loading = false;
});
}]);
.controller("UserController",
['$scope', '$routeParams', 'Users',
function ($scope, $routeParams, Users) {
$scope.loading = true;
$scope.user = Users.get({ userid: $routeParams.userid }, function () {
$scope.loading = false;
});
$scope.submit = function () {
$scope.user.$update(function () {
alert("Saved ok!");
});
}
}]);
.config(
['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$routeProvider
.when('/users', {
templateUrl: '/users.html',
controller: 'UsersController'
})
.when('/users/:userid', {
templateUrl: '/user.html',
controller: 'UserController'
})
.otherwise({ redirectTo: '/users' });
}
]
);
I am creating a form with several input options for the end user, but with one input which I would like to be an UUID/GUID.
Here's what I have so far for the module (project.js):
angular.module('project', ['ngRoute', 'firebase'])
.value('fbURL', 'https://private.firebaseio.com/')
.factory('Projects', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL));
})
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller:'ListCtrl',
templateUrl:'list.html'
})
.when('/edit/:projectId', {
controller:'EditCtrl',
templateUrl:'detail.php'
})
.when('/new', {
controller:'CreateCtrl',
templateUrl:'detail.php'
})
.otherwise({
redirectTo:'/'
});
})
.controller('ListCtrl', function($scope, Projects) {
$scope.projects = Projects;
$scope.project = { trackid: 'UUID' };
})
.controller('CreateCtrl', function($scope, $location, $timeout, Projects) {
$scope.project = { trackid: 'UUID' };
$scope.save = function() {
Projects.$add($scope.project, function() {
$timeout(function() { $location.path('/'); });
});
};
})
.controller('EditCtrl',
function($scope, $location, $routeParams, $firebase, fbURL) {
var projectUrl = fbURL + $routeParams.projectId;
$scope.project = $firebase(new Firebase(projectUrl));
$scope.destroy = function() {
$scope.project.$remove();
$location.path('/');
};
$scope.save = function() {
$scope.project.$save();
$location.path('/');
};
$scope.project = { trackid: 'UUID' };
});
And here's what I have for the form input (in my detail.php file):
<form name="myForm">
<label>Track ID</label>
<input type="text" name="trackid" ng-model="project.trackid" disabled>
As you can tell, in this example I'm simply inserting the text "UUID" where I would actually like to insert an UUID. I can't however seem to figure out how to insert a function there that would be generating this UUID. Any help would be very much appreciated! Thank you!
If you have a function that returns the value needed you can simply do:
function getUUID(){
var result = /* parse value */
return result;
}
$scope.project ={ trackid: getUUID() };
DEMO