AngularJs controller not getting called when a link is clicked - javascript

Currently, I'm working on an initial AngularJs app for an Admin Console for a database. I'm pretty new at Angular, so I've started off by modifying the phonecat tutorial. Basically, I've got a Jersey REST API that I need to make calls against in Angular. CORS is not the problem, they're both running on the same Tomcat.
The data structure is Projects have Groups within them.
I can redirect from Login to the Projects list page, the controller for getting the list of projects is called, and I can click a project and get the details page and its controller is called. But when I click a link from the project-details page and have it redirect to the groups-list page, the REST api call is never made (according to Chrome's network monitor.)
I'm rather confused because hypothetically it should be the exact same as the projects list.
Controllers:
phonecatControllers.controller('ProjectListCtrl', ['$scope', '$http',function($scope, $http){
$http.get('http://localhost:8080/WrappingServer/rest/api/project?show_hidden=true').success(function(data){
$scope.projects = data.hits.hits
});
$scope.orderprop='timeModified';
}]);
phonecatControllers.controller('GroupListCtrl', ['$scope', '$http',function($scope, $http){
$http.get('http://localhost:8080/WrappingServer/rest/api/group?projectID='+$scope.project._id+'&show_hidden=true').success(function(data){
$scope.groups = data.hits.hits //Yes this is correct. It's an elasticsearch cluster.
});
$scope.orderprop='timeModified';
}]);
phonecatControllers.controller('ProjectDetailCtrl', ['$scope', '$routeParams' ,'$http', function($scope, $routeParams, $http){
$http.get('http://localhost:8080/WrappingServer/rest/api/project/'+$routeParams.projectId).success(function(data){
$scope.project=data;
});
}]);
project-details.html:
<img ng-src="{{project._source.imageUrl}}" class="project">
<h1>{{project._source.name}}</h1>
<p>{{project._id}}</p>
<ul class="specs">
<a ng-href="#/groups" ng-click=>Group IDs</a>
<dd ng-repeat="group in project._source.groupIDs">{{proj._source.name}}
{{group.groupID}}
</dd>
</ul>
group-list.html
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
<!--Sidebar content-->
Search: <input ng-model="query">
Sort by:
<select ng-model="orderprop">
<option value="name">Alphabetical</option>
<option value="dateModified">Newest</option>
</select>
</div>
<div class="col-md-10">
<!--Body content-->
<ul class='groups'>
<li ng-repeat="group in groups | filter:query | orderBy:orderprop" class="thumbnail">
<img ng-src=" {{group._source.imageUrl}}" alt="{{group._source.name}}">
{{group._source.name}}
<p>{{group._source.timeModified}}</p>
</li>
</ul>
</div>
</div>
</div>
app.js
'use strict';
/* App Module */
var phonecatApp= angular.module('phonecatApp', [
'ngRoute', 'phonecatControllers', 'phonecatFilters']
);
phonecatApp.config(['$routeProvider',
function($routeProvider){
$routeProvider.when('/projects',
{
templateUrl: 'partials/project-list.html',
controller: 'ProjectListCtrl'
}).when('/projects/:projectId', {
templateUrl: 'partials/project-detail.html',
controller: 'ProjectDetailCtrl'
}).when('/home', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
}).when('/groups',
{
templateUrl: 'partials/group-list.html',
controller: 'GroupListCtrl'
})
.otherwise({
redirectTo: '/home'
});
}]);
I've even tried to take an approach where the projectID is a routeParam (kind of like for Project details), but still no luck.
Let me know if you anything else to answer my question. I know it's going to be something so stupidly simple that a handprint will appear on my forehead. (From what I've seen, possibly a space where it's not supposed to be.)
Thanks!

<a href="#/groups/{{group._id}}" class="thumb"> should be <a ng-href="/groups/{{group._id}}" class="thumb">
Also <a ng-href="#/groups" ng-click=>Group IDs</a should not have an empty ngClick on it. It should look like <a ng-href="/groups">.
So basically just change the attribute of the link from href to ng-href and then remove the # symbol from the link.

You have:
phonecatControllers.controller('GroupListCtrl', ['$scope', '$http',function($scope, $http){
$http.get('http://localhost:8080/WrappingServer/rest/api/group?projectID='+$scope.project._id+'&show_hidden=true').success(function(data){
$scope.groups = data.hits.hits //Yes this is correct. It's an elasticsearch cluster.
});
$scope.orderprop='timeModified';
}]);
I would instead do this in your controller:
phonecatControllers.controller('GroupListCtrl', ['$scope', '$http',function($scope, $http) {
$scope.function_name = function() {
$http.get('http://localhost:8080/WrappingServer/rest/api/group?projectID='+$scope.project._id+'&show_hidden=true').success(function(data){
$scope.groups = data.hits.hits //Yes this is correct. It's an elasticsearch cluster.
});
}
$scope.orderprop='timeModified';
}]);
For your link that is within the HTML element possessed by the controller,
<a ng-href="/groups" ng-click="function_name()">Group IDs</a>
As it is, your AJAX call is just sitting there. You need to place it within a block where code is executed for it to be called, just like in any other case. In this case, you must place it within a function that serves as a callback tied to ng-click.

Related

Angularjs nested controller called just one time

I'm new in Angularjs and I have an app, with some "projects", which have a local menu displayed on some pages. Index.html contains the main navbar with footer :
<body ng-app="ysi-app" ng-controller="MainController">
<div class="page-content">
<div class="row">
<div class="col-md-2">
<div class="sidebar content-box" style="display: block;">
<ul class="nav">
<!-- Main menu -->
<li ng-if="isAuthenticated()">{{name}}</li>
<li class="current">Dashboard</li>
<li>Projects</li>
</ul>
</div>
<div ng-if="isAuthenticated() && displayProjectMenu == true" ng-include="'views/localMenu.html'" ng-controller="LocalMenuController">
</div>
</div>
<div ng-view></div>
</div>
So I have a nested controller LocalMenuController for the local menu and a main controller. The project controller sets the datas :
angular.module('ProjectCtrl',[]).controller('ProjectController',function($scope,$location, ProjectService,$route, AuthenticationService, $rootScope){
$scope.setProjectDatas = function(projectName, projectId){
ProjectService.setName(projectName);
$rootScope.projectId = projectId;
};});
I set the id of one project to the $rootScope for testing (I have a Service which will do that better) and get it in the LocalMenuController :
angular.module('LocalMenuCtrl',[]).controller('LocalMenuController', function($scope, ProjectService, $rootScope) {
$scope.projectId = '';
$scope.projectId = $rootScope.projectId;
});
I display projects in a table and when I clicked on one of it, the function setProjectDatas(name,id) is called. The problem is when I clicked on one project, the id of the project is correct and set but when I go previous and clicked on another project, the id is the old id of the project previously clicked. The datas are not updating. I googled my problem but found nothing on it.
I think the LocalMenuController is called only one time but not after.
What am I doing wrong ?
Thank you
UPDATE
I've created a Directive which displays the template but it's still not updating the partial view localMenu.
LocalMenu Directive :
angular.module('LocalMenuCtrl',[]).controller('LocalMenuController', function($scope, ProjectService, $rootScope) {
console.log('-> LocalMenu controller');
})
.directive('localMenu', function($rootScope){
return {
templateUrl: '/YSI-Dev/public/views/partials/localMenu.html',
link: function(scope){
scope.projectId = $rootScope.projectId;
}
};
});
A part of index.html
<div ng-if="isAuthenticated() && displayProjectMenu == true" ng-controller="LocalMenuController">
<div local-menu></div>
</div>
Partial view localMenu :
<div class="sidebar content-box" style="display: block;">
<ul class="nav">
<li><i class="glyphicon glyphicon-list-alt"></i> Backlog</li>
<li><i class="glyphicon glyphicon-user"></i> My team </li>
</ul>
</div>
I'm trying to get the projectId from the $rootScope and inject it in the <a href="#/project/{{projectId}}" but I have some troubles. What's the way to do that ?
First of all, try using directives instead of ng-controller. You can encapsulate your code and template into a unit. You can also try creating a component. Pass some data to the directive/component and Angular will take care of updating the template and running whatever needs to run within the directive/component. (Given that you used two-way data-bindings)
From the code above, I cannot see what would trigger LocalMenuController to run again.

Ionic - Re-use the same HTML template for multiple pages with different content

I am building an Ionic app with multiple pages. A lot of these pages have the same HTML structure, only the content differs. How can I just use one HTML file and fill the content dynamically? Is this done via a controller per page? Or is there a better way to do this?
Here is an example of the HTML code for one page:
<ion-view title="Comparison">
<div class="bar bar-subheader bar-stable">
<h5 class="text-center">Do you have many categories?</h5>
</div>
<ion-content class="has-subheader">
<ion-list>
<ion-item ui-sref="bar-chart" class="text-center">Yes</ion-item>
<ion-item ui-sref="column-chart" class="text-center">No</ion-item>
</ion-list>
</ion-content>
So the parts that need to be dynamic per page are the title, h5 and list items.
Now I have a separate HTML file per page. I then refer to these HTML files in the .state in app.js as shown below.
.state('comparison-nb-categories', {
url: '/',
templateUrl: 'templates/comparison/nb-categories.html'
})
That page can be accessed from another page via an ui-sref as shown below.
<ion-item ui-sref="comparison-nb-categories" class="text-center">No</ion-item>
I think you can use one template html for all such pages but different controllers and in this controllers assign right values to model.
.state('state1', {
templateUrl: "templates/page1.html",
controller: "FirstCtrl",
})
.state('state2', {
templateUrl: "templates/page1.html",
controller: "SecondCtrl",
});
html would be
<ion-view title="{{title}}">
<div class="bar bar-subheader bar-stable">
<h5 class="text-center">{{subheader}}</h5>
</div>
<ion-content class="has-subheader">
<ion-list ng-repeat="item in items">
<ion-item ui-sref="{{item.ref}}bar-chart" class="text-center">{{item.name}}</ion-item>
</ion-list>
</ion-content>
FirstCtrl
.controller('FirstCtrl', ['$scope', function ($scope) {
$scope.title = Title1;
$scope.subheader = Subheader1;
$scope.items = [{name:'Yes', ref:'bar-chart'},{name:'No', ref:'column-chart'}];
SecondCtrl
.controller('SecondCtrl', ['$scope', function ($scope) {
$scope.title = Title2;
$scope.subheader = Subheader2;
$scope.items = [{name:'name1', ref:'ref1'},{name:'name2', ref:'ref2'}];
I added working example http://codepen.io/anon/pen/bEpKJE?editors=101

angularjs - array updated but view did not update when using ui-router

I use ui-router to route to particular sub page as needed:
var myApp = angular.module("myApp",['ui.router']);
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('usergroups', {
url: "/usergroups",
templateUrl: "pages/usergroups.html",
controller : 'UsergroupsCtrl'
})
.state('usergroups.create', {
url: "/create",
templateUrl: "pages/usergroups.new.html",
controller : 'UsergroupsCtrl'
})
...
This is my usergroups.html:
<body>
<h3>User Groups</h3><br/>
<button class="fon-btn" type="button" ng-hide = "toAdd" ng-click="toAdd = true" ui-sref="usergroups.create">Create New Group</button>
<div ui-view></div>
<ul>
<li class="bitcard padding10" ng-repeat="group in usergroups">
<span class="padding10"><strong>{{group.name}}</strong></span>
</li>
</ul>
</body>
and usergroups.new.html:
<body>
<form ng-submit="add()">
<input class="btn" type="submit" value="Add Usergroup"><br/><br/>
</form>
</body>
When I click on Add Usergroup, it will called add() from UsergroupsCtrl:
$scope.add = function() {
$scope.usergroups.push({name:$scope.name});
console.log($scope.usergroups);
}
The console show that $scope.usergroups is already updated. but somehow in usergroups.html: ng-repeat="group in usergroups" did not update the view. I add $scope.$apply() and $scope.$digest() but got an error:
$apply already in progress
But everything works fine if I did not use ui-router. How can I resolve this?
I think same $scope cannot be used in two different controllers. you can change it to $rootScope. like $rootScope.usergroups.push(). This SO may help you. You can use $stateParam also.

How to update content based on sidebar in AngularJS

I asked a question yesterday How to do multiple views with Angular to support header and sidebar? and based on that question I was able to make some progress in having a header and a sidebar for my AngularJS App.
I've got a working fiddle here: http://jsfiddle.net/mcVfK/929/
The JS looks like this:
angular.module('app', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/header1', {
templateUrl: 'header1.html',
controller: DashboardCtrl
})
.when('/header2', {
templateUrl: 'header2.html',
controller: DashboardCtrl
})
.when('/dashboard',{
templateUrl: 'dashboard.html',
controller: DashboardCtrl
})
.when('/sidebar1',{
templateUrl: 'sidebarlink1.html',
controller: DashboardCtrl
})
.when('/sidebar2',{
templateUrl: 'sidebarlink2.html',
controller: DashboardCtrl
})
.otherwise({
redirectTo: '/header1'
});
}]);
function DashboardCtrl() {
}
This seems to work, however, I want to find out whether there is a way to avoid including sidebar.html on every link in the sidebar?
If you notice on the fiddle, I'm doing this:
<script type="text/ng-template" id="sidebarlink1.html">
<div ng-include="'sidebar.html'" id="sidebar"></div>
sidebar link 1 content - including sidebar
</script>
<script type="text/ng-template" id="sidebarlink2.html">
<div ng-include="'sidebar.html'" id="sidebar"></div>
sidebar link 2 content - including sidebar
</script>
So I'm including sidebar.html on every link in the sidebar. I'm wondering if there is a way to avoid this? Also, is there an Angular way to highlight which sidebar link is currently active?
You can move the sidebar include out and use a variable to determine in what route you want to see it. Check out this jsfiddle:
http://jsfiddle.net/mcVfK/931/
angular.module('app', ['ngRoute'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/header1', {
templateUrl: 'header1.html',
controller: DashboardCtrl,
resolve: {
hasSidebar: function($rootScope) {
$rootScope.hasSidebar = false;
return false; }
}
})
I recomend to use ui-router (What is the difference between angular-route and angular-ui-router?) instead of ngRoute. Lear about it if you are interested. And then use some ng-switch like this:
//Parent template
<script type="text/ng-template" id="sidebarlinkparent.html">
<div ng-include="'sidebar.html'" id="sidebar"></div>
<div ng-switch="$state.current.name">
<div ng-switch-when="sidebar1" ng-include="'sidebarlink1.html'"></div>
<div ng-switch-when="sidebar2" ng-include="'sidebarlink2.html'"></div>
</div>
</script>
//template sidebar 1
<script type="text/ng-template" id="sidebarlink1.html">
sidebar link 1 content - including sidebar
</script>
//template sidebar 2
<script type="text/ng-template" id="sidebarlink2.html">
sidebar link 2 content - including sidebar
</script>
Then change your templateUrl in route config to go at the parent template sidebarlinkparent.html on /sidebar1 and /sidebar2
Aswell you can use your actual ngRoute and change the ngSwitch condition with a controller scope var setted on routes or something like that
EDIT:
OPTION 2:
//Parent template
<script type="text/ng-template" id="sidebarlinkparent.html">
<div ng-include="'sidebar.html'" id="sidebar"></div>
<div ng-include="$state.current.name +'.html'"></div>
</script>
OPTION 3:
//Parent template
<script type="text/ng-template" id="sidebarlinkparent.html">
<div ng-include="'sidebar.html'" id="sidebar"></div>
<div ng-include="$state.params.include +'.html'"></div>
</script>
etc etc..

AngularJS 1.3 Routing not working; Controller never called

I can't for the life of me get AngularJS to work properly. I am not messing with templates or anything of that nature yet, I'm just trying to get the call to the controller to work correctly.
Here is a portion of my homepage.html
<div class="row" ng-app="eventsApp">
<div class="column small-12 content">
<p>Temporary Test.</p>
<div ng-view></div>
<ul class="small-block-grid-2 medium-block-grid-4 large-block-grid-5 shots">
<li>
<div class="thumb">
<a href="#Testing">
<div class="ctr-show s1">
<div class="show"><i class="fa fa-search-plus fa-lg"></i></div>
</div>
<img src="/img/screenshots/thumbs/g" alt="">
</a>
</div>
</li>
...
Here is my app.js
'use strict';
var eventsApp = angular.module('eventsApp', [
'ngRoute',
'ngSanitize',
]);
alert("testing number 1");
eventsApp.config(['$routeProvider', function($routeProvider){
$routeProvider.
when('/Testing', {
templateUrl : 'Views/AngularViews/temp.html',
controller : 'TestingController'
});
}]);
Later on in the app.js....
eventsApp.controller('TestingController',
function($scope) {
alert("testing number 2");
});
Can anyone spot what I'm doing incorrectly? It just isn't working at all. The first alert pops up just fine, the second one never pops up, even after using the correct route.
Thanks in advance.
This is my code in coffeescript that works, I cannot spot any error in your implementation (and since there is no error on console...)
App.config [
'$provide'
'$routeProvider'
($provide, $routeProvider) ->
$routeProvider
.when('/testing', {
templateUrl: 'test.hml'
controller : 'TestingController'
})
]
iDsign.App.controller('TestingController', ($scope)->
alert('something')
)

Categories