I am new to angularJS. I am currently building a small mobile store where I display the data of all the products in the front page and on clicking the product, i wanted to show the description of the product in the next page.
When I click on the product, I was able to redirect to the next page but not the contents of the page.
My index.html
<div class="container">
<header>
<h1>My Mobile Store</h1>
</header>
<hr class="header-seperator">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">My Mobile Store</a>
</div>
<div>
<ul class="nav navbar-nav">
<li class="active">Mobiles</li>
<li>Electronics</li>
<li>Fashions</li>
<li>Footwears</li>
</ul>
</div>
</div>
</nav>
<div ng-view></div>
</div>
My app.js
(function() {
var storeConfig = function($routeProvider) {
$routeProvider
.when('/', {
controller: 'StoreController',
templateUrl: 'views/products-list.html',
controllerAs: 'StreCtrl'
})
.when('/product', {
controller: 'StoreController',
templateUrl: 'views/product.html',
controllerAs: 'prodCtrl'
});
};
var app= angular.module('mystore',['ngRoute']).config(storeConfig);
app.service('sharedProperties', function () {
var product = [];
return {
getProduct: function () {
console.log(product);
return product;
},
setProduct: function(value) {
product = value;
//console.log(product);
}
};
});
app.controller('StoreController',[ '$http', 'sharedProperties', function($http,sharedProperties) {
var store = this;
store.products = [];
store.error = "false";
store.item = [];
$http.get('data/products.json').success(function(data) {
store.products = data;
}).error(function() {
store.error = "true";
});
store.showProduct = function(product) {
sharedProperties.setProduct(product);
};
store.item = sharedProperties.getProduct;
console.log("Store Item");
console.log(store.item);
}]);
})();
I couldn't get the data in store.item. What is the mistake I am doing. Any help will be grateful.
Thanks in Advance!!
You are assigning a method reference to your scope object, Instead of you need to call method.
Change From
store.item = sharedProperties.getProduct;
TO
store.item = sharedProperties.getProduct();
Related
For the purposes of navigation, I'm trying to have a button that triggers a function.
This function must first:
-Redirect to #/
And then:
-Filter an ng-repeat that exists in this view.
This is what I've tried but no luck.
<li><a ng-click="shopsingle()">Shop</a></li>
And JS:
$scope.shopsingle = function(){
$location.path("/");
setTimeout(function () {
$scope.$apply(function(){
$scope.filterExpr = {"shop" : true};
console.log($scope.filterExpr);
});
}, 300);
};
It does redirect to the desired path, where a full ng-repeat list appears, but it won't apply the filter, and console also comes empty.
About the views and routing, I'm using the same template for 2 different views, and showing/hidding parts of if while watching the $routeParams:
.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "home.htm",
controller : "mainCtrl"
})
.when('/:name',
{
templateUrl:"home.htm",
controller:"mainCtrl"
})
.otherwise({redirectTo:'/'});
})
And the controller watch:
$scope.name = $routeParams.name;
$scope.$watch(function() { return $scope.name; }, function(newVal) {
if (!newVal){
$scope.single = false;
} else{
$scope.single = true
};
$scope.newname = newVal;
$scope.chosenexhibitor = $filter("filter")($scope.images, {'name':$scope.newname}, true);
}, true);
And the view:
<!-- MAIN PAGE -->
<div ng-hide="single" id="tiles" masonry='{ "transitionDuration" : "0.15s" , "itemSelector" : ".tile"}'>
<div masonry-tile ng-repeat="item in images | filter:filterExpr" class="tile col-xs-3 col-md-3">
<a href="#/{{item.name}}">
<img class="img-fluid" ng-src="img/{{item.link}}">
</a>
</div>
</div>
<!-- SINGLE PAGE -->
<div class="row flexing" ng-show="single">
<div class="col-md-12">
<h1>{{chosenexhibitor[0].name}}</h1>
<img ng-src="img/{{chosenexhibitor[0].link}}">
<a class="back" href="#/">Back</a>
</div>
</div>
What am I missing?
The aboutus.html page is displayed correctly, except the content in the ng-repeat within media-list in aboutus.html. there are no errors displayed in the console. I have not included the entire code (since it takes more space.). Can anyone help me?
// factory here.
angular.module('vasuapp')
.factory('corporateFactory', function() {
// Implement two functions, one named getLeaders,
// the other named getLeader(index)
// Remember this is a factory not a service
var corpfac = {};
var leadership = [
{
id: 0,
name:"asdfd",
designation:"sgsdgg",
abbr: "fgdfvf",
},
{
// similarly some other data here.
} ];
corpfac.getLeader = function(){
return leadership;
};
corpfac.getLeaders = function(index)
{
return leadership[index];
};
return corpfac;
});
// app.js
angular.module('vasuapp', ['ngRoute'])
.config(function($routeProvider) {
$routeProvider
.when('/aboutus', {templateUrl:'./aboutus.html' , controller: 'AboutController'})
.otherwise('/');
})
// controller.js
angular.module('vasuapp')
.controller ('AboutController',['$scope','corporateFactory', function($scope,corporateFactory){
var leadership = corporateFactory.getLeader();
$scope.leaders = this.leadership;
}])
// aboutus.html
<div class="row row-content">
<div class="col-xs-12 col-sm-9">
<h2>Corporate Leadership</h2>
<p> hi </p>
<ul class="media-list">
<li class = "media" ng-repeat = "lead in leaders">
<div class = "media-list tab-pane fade in active">
<a ng-href="#/aboutus">
<img class = "media-object" ng-src={{lead.image}} alt="author image">
</a>
</div>
<div class = "media-body">
<p>{{lead.description}}</p>
</div>
<footer>
-- {{lead.name}} the {{lead.designation}}
</footer>
</li>
</ul>
</div>
I think what you want is:
$scope.leaders = corporateFactory.getLeader();
this.leadership is not defined.
I have to make app for listing recent photos from Flickr with option when click on any image to show that image with tags and comments it contains.
I've made this:
core.module.js
(function () {
'use strict';
angular.module('flickrApp.core', ['ui.router', 'ngResource']);
})();
core.factory.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.factory('flickrImgs', flickrImgs);
flickrImgs.$inject = ['$http'];
function flickrImgs($http) {
var url = 'https://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=415028ef16a31ed8f70f9dc3e90964d1&extras=url_q,url_o,tags&format=json&nojsoncallback=1';
var photos;
var factory = {
getPhotos: getPhotos
};
return factory;
function getPhotos() {
return $http.get(url).then(function (response) {
factory.photos = response.data.photos.photo;
});
}
};
})();
core.controller.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.controller('flickrController', flickrController);
flickrController.$inject = ['flickrImgs', '$location', '$http'];
function flickrController(flickrImgs, $location, $http) {
var fc = this;
fc.showImg = function (id) {
$location.path("/photos/" + id);
console.log(id);
};
flickrImgs.getPhotos().then(function () {
fc.photos = flickrImgs.photos;
});
}
})();
core.router.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.config(config);
config.$inject = ['$stateProvider', '$urlRouterProvider'];
function config($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('main', {
abstract: true,
views: {
'header': {
templateUrl: 'app/components/core/header.html'
}
}
})
.state('main.home', {
url: '/home',
views: {
'content#': {
templateUrl: 'app/components/core/home.html',
controller: 'flickrController',
controllerAs: 'fc'
}
}
})
.state('main.singleImg', {
url: '/photos/:id',
views: {
'content#': {
templateUrl: 'app/components/core/single-img.html',
controller: 'flickrController',
controllerAs: 'fc'
}
}
});
newPhoto.$inject = ['$stateParams', 'flickrImgs'];
function newPhoto($stateParams, flickrImgs) {
return flickrImgs.get({
id: $stateParams.id
}).$promise;
}
}
})();
home.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | limitTo:16" class="col-sm-12 col-md-3">
<a href ng-click="fc.showImg(photo.id)">
<img class="thumbnail" ng-src="{{photo.url_q}}" width="100%">
</a>
</div>
</div>
single-img.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | filter : {id: photo.id} | limitTo: 1" class="col-sm-12 col-md-10 col-md-offset-1">
<a href ng-click="fc.showImg(photo.id)">
<img class="thumbnail" ng-src="{{photo.url_o}}" width="100%">
</a>
<div>Tags:
<button class="btn-primary">
{{photo.tags}}
</button>
</div>
<div>Comments:
<div>
{{photo.comments}}
</div>
</div>
</div>
</div>
When I click on image listed on home page, I want to pass that image to single-img.html template and I get image id in url, but I don't know how to pass it to html.
Any help would be appreciated.
You are missing ui-sref in in home.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | limitTo:16" class="col-sm-12 col-md-3">
<a ui-sref="main.singleImg({id: photo.id})">
<img class="thumbnail" ng-src="{{photo.url_q}}" width="100%">
</a>
</div>
</div>
// Updated flickrImgs factory method
function getPhotos() {
var deferred = $q.defer();
if (factory.photos) {
deferred.resolve(factory.photos);
} else {
$http.get(url).then(function(response) {
factory.photos = response.data.photos.photo;
deferred.resolve(factory.photos);
});
}
return deferred.promise;
}
// single image state with new controller
.state('main.singleImg', {
url: '/photos/:id',
views: {
'content#': {
templateUrl: 'app/components/core/single-img.html',
controller: 'singleImgController',
controllerAs: 'sic'
}
}
});
// New Controller
angular
.module('flickrApp.core')
.controller('singleImgController', singleImgController);
singleImgController.$inject = ['$stateParams', 'flickrImgs'];
function singleImgController($stateParams, flickrImgs) {
var vm = this;
flickrImgs.getPhotos()
.then(function(photos) {
angular.forEach(photos, function(photo) {
if(photo.id == $stateParams.id) {
vm.photo = photo;
}
})
});
}
// New single-img.html
<div class="row col-sm-12 col-md-8 col-md-offset-2">
<img class="thumbnail" ng-src="{{sic.photo.url_o}}" width="100%">
<div>Tags:
<div class="btn-primary">
{{sic.photo.tags}}
</div>
</div>
<div>Comments:
<div>
{{sic.photo.comments}}
</div>
</div>
</div>
Hope this helps.
I'm trying to create an SPA website where I have multiple controllers that depend on an AuthService, this service is just in charge of telling all the controllers if the User is signedIn and who the user is. AFAIK since all the controllers share the same service object, the changes should propagate to them, but so far this is not happening.
My code goes as follows:
I have a NavbarController and a LoginController. The NavbarController is in charge of displaying the Login/Logout links depending on the Logged property of the AuthService. The LoginController is in charge of the login panel and calling the login on the server through the AuthService.
AuthService
(function () {
var auth = angular.module('Auth', []);
auth.factory('AuthService', ['$http', function ($http) {
var obj = {};
obj.User = {};
obj.Logged = true;
obj.GetUser = function () {
$http.get('api/Account/UserDetails')
.success(function (data) {
obj.User = data;
obj.Logged = true;
})
}
obj.Login = function (data) {
var func = $http.post('api/Account/Login', data);
func.success(function (data) {
if (data.StatusCode == 200) {
obj.GetUser();
}
});
return func;
}
obj.Logoff = function () {
$http.get('api/Account/Logoff')
.success(function () {
obj.User = {};
obj.Logged = false;
});
}
return obj;
}]);
})();
LoginController
(function () {
var login = angular.module('Login', ['LoginService','Auth']);
login.controller('LoginController', ['accountService','AuthService', function (accountService,authService) {
this.OnFocus = function(obj)
{
$(obj.target).closest(".textbox-wrap").addClass("focused");
}
this.OnBlur = function(obj)
{
$(obj.target).closest(".textbox-wrap").removeClass("focused");
}
this.loginCredentials = {};
this.Login = function () {
authService.Login(this.loginCredentials)
.success(function (data) {
alert(data.StatusCode);
})
.error(function () {
alert("error");
});
}
}]);
login.directive('hcCheckbox', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.iCheck({
checkboxClass: 'icheckbox_square-blue',
increaseArea: '20%' // optional
});
}
}
});
})();
NavbarController
(function () {
var app = angular.module('main');
app.controller('NavbarController', ['AuthService', function (AuthService) {
var self = this;
self.Logged = AuthService.Logged;
self.User = AuthService.User;
self.Logoff = function()
{
AuthService.Logoff();
}
}]);
})();
Navbar html template
<nav class="navbar navbar-default" ng-controller="NavbarController as NavbarCtrl">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="navegacion">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">HACSYS</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="navegacion">
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Details</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li ng-hide="NavbarCtrl.Logged">
Login
</li>
<li ng-show="NavbarCtrl.Logged">
<a ng-click="NavbarCtrl.Logoff()" href=""> Logoff</a>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
I know I could use $watch to propagate changes to other controllers, but this way seems cleaner to me, I have seen other examples where this works, and I still can't figure out whats going wrong with my code
In order to ensure that changes are propagated correctly across all the nested scopes, you need to bind to an object by reference. If you bind to a primitive, it creates a copy of the value on scope, effectively breaking the linkage between the scope variables. To resolve this, bind by reference:
app.controller('NavbarController', ['AuthService', '$scope', function (AuthService, $scope) {
var self = this;
$scope.AuthService = AuthService;
self.Logoff = function()
{
$scope.AuthService.Logoff();
}
}]);
When you bind by reference, any controller where you inject AuthService will bind and propagate as expected.
app.controller('otherController', function($scope, AuthService) {
$scope.AuthService = AuthService;
});
HTML
<div ng-controller="otherController">
<div ng-show="AuthService.Logged">
User is logged in!
</div>
</div>
I have a grid like this
<div ng-controller="UserCtrl">
...
<div class="grid">
<div class="grid-header">
<h3>Showing {{users.records}} Users</h3>
</div>
<div class="grid-con">
<div class="grid-con-header row">
<div ng-click="sortOrder($event, 'fullName')" class="col-xs-4 sortable"><span>Name</span></div>
<div ng-click="sortOrder($event, 'emailAddress')" class="col-xs-4 sortable"><span>Email</span></div>
<div class="col-xs-4"></div>
</div>
<div class="grid-con-body">
<div ng-hide="isGridLoading" class="row" ng-repeat="row in users.rows">
<div class="col-xs-2">
{{row.fullName}}
</div>
<div class="col-xs-3">{{row.emailAddress}}</div>
<div class="col-xs-3">
<a ng-href="#/users/modify/{{row.loginId}}" type="button" class="btn btn-success">Modify</a>
</div>
</div>
<div class="row ajax-ngview" ng-show="isGridLoading"></div>
</div>
</div>
</div>
</div>
Here is my UserCtrl
function UsersCtrl($scope, Users) {
$scope.grid = {
"_search": '',
"page": 1,
"rows": 10,
"sidx": "loginId",
"sord": "asc"
};
$scope.users = {};
updateGrid();
function updateGrid() {
$scope.isGridLoading = true;
Users.get($scope.grid).$promise.then(function(result) {
$scope.users = result;
$scope.isGridLoading = false;
}, function(reason) {
});
}
$scope.sortOrder = function(event, name) {
...
}
}
I want to show this type of grid on multiple pages, I am not sure what best solution is here. Do I need to copy the UserCtrl and paste it as some like GroupCtrol and modify it as required or is there some better solution?
You could use $routeProvider's resolve property, to pass the appropriate model as a dependency:
/* First "generify" the controller */
angular.module('myApp').controller('gridCtrl', function ($scope, Data) {
$scope.grid = {
"_search": '',
"page": 1,
"rows": 10,
"sidx": "loginId",
"sord": "asc"
};
$scope.data = {};
updateGrid();
function updateGrid() {
$scope.isGridLoading = true;
Data.get($scope.grid).$promise.then(function (result) {
$scope.data = result;
$scope.isGridLoading = false;
}, function (reason) {...});
}
...
/* Second, configure $routeProvider to pass
* the appropriate model to each view */
angular.module('myApp').config(function ($routeProvider) {
$routeProvider
.when('/users', {
templateUrl: 'grid.html',
controller: 'gridCtrl',
resolve: {
Data: 'Users'
}
})
.when('/groups', {
templateUrl: 'grid.html',
controller: 'gridCtrl',
resolve: {
Data: 'Groups'
}
});
So, in the 1st case the Users service will be passed as a dependency to the gridCtrl controller (under the name of Data), whereas in the 2nd case the Groups service will be passed (again under the name of Data).
For what it's worth, I too do believe a directive would be more appropriate here...