I've a module where I configure a route like this :
var app = angular.module("myModule", ['ui.grid','ui.bootstrap','ngRoute']);
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController'
})
}
In the template page I configure the controller like this :
<script src="/Scripts/SPScripts/Services/SubjectService.js"></script>
<script src="/Scripts/SPScripts/Controllers/SubjectController.js"></script>
<div id="dvcollection" data-ng-controller="SubjectController">
<div style="padding-left: 15px; padding-bottom: 10px;">
<button type="button" id="addRow" class="btn btn-success" data-ng-click="addRow()">Nuovo</button>
</div>
<div class="gridStyle" data-ui-grid="gridOptions"></div>
</div>
In this way the controller is undefinied and seems that the scripts aren't loaded in the page correctly.
If I move the scripts in my Master Page (where I load the angular module) the controller is loaded correctly.
MasterPage :
<script src="/Scripts/SPScripts/Modules/Module.js"></script>
<div class="container body-content" data-ng-app="myModule">
<div data-ng-view></div>
</div>
I would like to load the various controllers on the pages where are needed so as not to burden the application, since they are loaded all into the master page.
**** - EDIT - ****
Seems that I can load scripts by using the 'resolve' in route :
var resolveController = function (path) {
var deferred = $q.defer();
var script = document.createElement('script');
script.src = path;
script.onload = function () {
$scope.$apply(deferred.resolve());
};
document.body.appendChild(script);
return deferred.promise;
};
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController',
resolve: resolveController('/Scripts/SubjectController.js')
})
}
But I retrieve the error : $q is not defined.
Is it the correct way?
try this : remove data-ng-controller="SubjectController" from template
In Your Angular Module File :
var app = angular.module("myModule", ['ui.grid','ui.bootstrap','ngRoute']);
app.config([ $routeProvider , function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController'
});
}])
Then in Your Template File
<div id="dvcollection" >
<div style="padding-left: 15px; padding-bottom: 10px;">
<button type="button" id="addRow" class="btn btn-success" data-ng-click="addRow()">Nuovo</button>
</div>
<div class="gridStyle" data-ui-grid="gridOptions"></div>
</div>
In Your master Page
<script src="/Scripts/SPScripts/Modules/Module.js"></script>
<div class="container body-content" data-ng-app="myModule">
<div data-ng-view></div>
</div>
after your edit it seems you didn't 'inject' $q in your resolver :
var resolveController = function ($q,$rootscope) {
var deferred = $q.defer();
var script = document.createElement('script');
script.src = '/Scripts/SubjectController.js';
script.onload = function () {
$rootscope.$apply(deferred.resolve());
};
document.body.appendChild(script);
return deferred.promise;
};
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController',
resolve: { resolveController: resolveController
})
}
I've replaced $scope with $rootscope and injected it as $scope isn't defined.
Hope this help, found this question on the subject with a interesting discussion about it.
You need to do this:
$injector = angular.injector(['ng']);
q = $injector.get('$q');
var deferred = q.defer();
Related
Im new to angularjs and Im currently learning on angular's ng-route. I already done on it but what I want to achieve is to display first the loading message before displaying the content of the address of the route.
What's happening on my code right now is like this:
1. Click the home link
2. Display the loading message on the current page before successfully loading the content of the home link
That's how my code works, and I don't want it that way.
What I want to happen is something like this:
1. Click the home link
2. Current page will be hidden and display the loading message before displaying the content of the home link
I hope you understand. By the way here's my code:
index.html
<body ng-app="myApp" ng-controller="mainController">
<i class="fa fa-shield"></i> main
<i class="fa fa-home"></i> home
<!-- start views -->
<div ng-view></div>
</body>
script.js
var app = angular.module('myApp', ['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: 'main.html',
controller: 'mainController',
resolve:{
delay: function($q, $timeout){
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.when('/home',{
templateUrl: 'home.html',
controller: 'homeController',
resolve:{
delay: function($q, $timeout){
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.otherwise({
redirectTo: '/'
});
});
app.controller('mainController', function($scope){
$scope.message = "...";
});
app.controller('homeController', function($scope){
$scope.message = "...";
});
app.directive('showDuringResolve', function($rootScope) {
return {
link: function(scope, element) {
element.addClass('ng-hide');
var unregister = $rootScope.$on('$routeChangeStart', function() {
element.removeClass('ng-hide');
});
$scope.$on('$destroy', unregister);
}
};
});
main.html
<h1>Main Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
home.html
<h1>Home Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
you can achieve the desired behavior with few modification in your code.
Add the loader text in your index.html file and show/hide the ng-view and loading text based on the rootScope variable statechange
<div ng-view ng-show="statechange"></div>
<div ng-show="!statechange" show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.</div>
in your directive make the following change.
app.directive('showDuringResolve', function($rootScope) {
return {
link: function(scope, element) {
element.addClass('ng-hide');
$rootScope.statechange = true;
var unregister = $rootScope.$on('$routeChangeStart', function() {
element.removeClass('ng-hide');
$rootScope.statechange = false;
});
scope.$on('$destroy', unregister);
}
};
});
Plunker : https://plnkr.co/edit/RISv2lvxwf75nuVfWLgA?p=preview
You can use a variable in each controller like dataReady, so for example in your home page, you can do something like:
html:
<div ng-show="dataReady">
<h1>Home Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
</div>
<div ng-show="!dataReady">
<h1> Loading ...</h1>
</div>
js:
app.controller('homeController', function($scope){
$scope.message = "...";
// After all the logic
$scope.dataReady = true;
});
And repeat the same idea for all the pages that you need.
By default set the loader to be hide
<strong class="loader" id="loader">Loading....</strong>
.loader{
display: none;
}
.loader-show{
display: inline-block;
}
When request made to get data, show the loader by adding loader-show class. On successful completion of request, hide loader by removing loader-show class.
That is,
resolve:{
delay: function($q, $timeout){
var loader = document.getElementById('loader');
loader.addClass('loader-show'); // when request is going to made
var delay = $q.defer();
$timeout(delay.resolve, 1000);
loader.removeClass('loader-show'); // when request ends
return delay.promise;
}
}
I have build a very basic Angular Router. But now that I want to interact with my elements inside that templateUrl, no javascript gets executed or those elements inside the templateUrl can not be accessed. I have copied the most of the code from this instruction, here.
My index file:
<html ng-app="myApp">
<head></head>
<body ng-controller="mainController">
<a id="btnHome" href="#/">Startseite</a>
<a id="btnPlanner" href="#/planner">LTC-Planner</a>
<a id="btnSocial" href="#/social">LTC-Social</a>
<div id="main">
<!-- angular content -->
<div ng-view></div>
</div>
<script src="js/routing.js"></script>
</body>
</html>
This is my routing.js file:
// Create the angular module
var myApp = angular.module('myApp', ['ngRoute']);
// Configure our routes
myApp.config(function($routeProvider) {
$routeProvider
// Route for the home page
.when('/', {
templateUrl: 'pages/home.html',
controller: 'mainController'
});
});
// Create the controller and inject angular's $scope
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
});
and this is the template file located at pages/home.html:
<button id="btnTest">Say Hello</button>
<script>
var btnTest = document.getElementById('btnTest');
btnTest.addEventListener('click', function(){
console.log('Hello');
});
</script>
maybe one of you got an idea or has seen an alternative.
Thanks,
André
you should try to wrap your html template in a single tag
<div>
<button ng-click="test()">Say Hello</button>
</div>
And remove the script to put the logic inside your controller. Since your using angular, just use ng-click to bind click listener.
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
$scope.test = function() {
console.log('Hello');
}
});
I am trying to develop an application using angularjs+mvc+api.as you can see here my angular js module and controller :
//home-index.js
var myApp = angular.module('myApp', []);
myApp.config([function ($routeProvider) {
$routeProvider.when("/", {
Controller: "homeIndexController",
templateUrl:"templates/t.html"
});
$routeProvider.otherwise("/");
}]);
myApp.controller('homeIndexController', homeIndexController);
function homeIndexController($scope,$http) {
$scope.data2 = [];
$scope.busy = true;
$http.get("/api/default").
then(function(result) {
//success
angular.copy(result.data, $scope.data2);
}, function() {
//error
}).then(function() {
$scope.busy = false;
});
}
As you can i create a routing .so if the user enter this url http://localhost:20713/Home/Index/#/ the angular should load the t.html in my templates folder .
I have a view that the t.html should be injected to it ,as you can see here :
#{
ViewBag.Title = "Home Page";
}
<div data-ng-view=""></div>
here is the content of t.html file :
Hi this is a test
But when i call this url http://localhost:20713/Home/Index/#/ nothing happens!!and the page is empty and the message Hi this is a test doesn't exist in it .why ?
The resource of my page in the browser
Inject ngRoute module on your myApp module
var myApp = angular.module('myApp', ['ngRoute']);
And specify array inline annotations properly
myApp.config('$routeProvider', [function ($routeProvider) {
$routeProvider.when("/", {
Controller: "homeIndexController",
templateUrl:"templates/t.html"
});
$routeProvider.otherwise("/");
}]);
I just change the reference of angular js
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
and every thing works fine .why ?
Try
<div ng-app="myApp">
<div ng-view></div>
</div>
and also change
Controller: "homeIndexController"
to
controller: "homeIndexController",
I have converted one of my Angular controllers to Controller As syntax, but I am having trouble getting an ng-grid template to play nicely.
The controller has a function called edit user that looks like this
self.editUser = function (user_data) {
var modalInstance = $modal.open({
templateUrl: '/admin/views/adminuser.html',
controller: 'AdminUserController',
resolve: {
user_data: function () {
return user_data;
}
}
});
modalInstance.result.then(function () {
self.myQueryData.refresh = !self.myQueryData.refresh;
});
};
the ng-grid template looks like this
<div class="ngCellText" ng-class="col.colIndex()">
<a ng-click="$parent.$parent.$parent.$parent.editUser({user_id:row.entity.id, first_name:row.entity.first_name, last_name:row.entity.last_name, email:row.entity.email})">
<span ng-cell-text translate>Edit</span>
</a>
</div>
and my route looks like this
.when('/admin/settings', {
templateUrl: '/admin/views/settings.html',
controller: 'SettingsController as sc',
})
So the problem is in the template when I call
$parent.$parent.$parent.$parent.editUser
it doesn't know what I am talking about unless I include the controller name like
$parent.$parent.$parent.$parent.sc.editUser,
then it works great. However I don't want to bind this template directly to the sc controller. How can I call the editUser without using the controller name?
I was hoping there would be a function on the $parent that would supply the function name like
$parent.$parent.$parent.$parent.getController().editUser
Any suggestions?
You can call functions on parent scope directly without referring to $parent. Because you might get in to trouble later when you modify your view structure.
example:
<div ng-app="MyApp">
<div ng-controller="MyController">
{{myMessage}}
<div ng-controller="MyController2">
<div ng-controller="MyController3">
<div ng-controller="MyController4">
<button id="myButton" ng-click="setMessage('second')">Press</button>
</div>
</div>
</div>
<script>
angular.module('MyApp', [])
.controller('MyController', function($scope) {
$scope.myMessage = "First";
$scope.setMessage = function(msg) {
$scope.myMessage = msg;
};
}).controller('MyController2', function($scope) {
}).controller('MyController3', function($scope) {
}).controller('MyController4', function($scope) {
});
</script>
</div>
</div>
Or else you can use angular $broadcast
Since you are using controllerAs syntax, you can address your controller by the alias, so the actual template line will look like this:
<a ng-click="sc.editUser({user_id:row.entity.id, first_name:row.entity.first_name, last_name:row.entity.last_name, email:row.entity.email})">
Plunker
There are a lot of files, so perhaps you Angular aficionados will understand my explanation, or be able to follow the plunker I've provided above.
I'm creating a demo to modularize a webpage. Even the main content of the page will be in another template file. In the main content view, there's a table of links, the link opens an angular-bootstrap modal (another template/controller), which displays additional information for the object clicked.
I'm finding that every time a link is clicked, the factory is retrieving the source data. For something small, it's unnoticeable, but if you're performing an AJAX request to a large dataset, or transforming an XML to JSON, this could take a while. I am uncertain if this is a result of routing, or if it's a poor implementation of what I'm trying to accomplish, but I would like to:
understand why this is happening
retrieve the initial data once and share it between controllers
data.json
[
{"firstName":"John",
"lastName":"Denohn",
"profession":"Student",
"age":10
},
{"firstName":"Mark",
"lastName":"Fatzigio",
"profession":"Doctor",
"age":20
},
{"firstName":"Jennifer",
"lastName":"Cooler",
"profession":null,
"age":30
},
{"firstName":"Kimberly",
"lastName":"Branch",
"profession":"Teacher",
"age":40
}
]
index.html
<!DOCTYPE html>
<html lang="en" data-ng-app="myApp">
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<link href="myApp.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
</head>
<body>
<div data-ng-view="" data-ng-cloak ></div>
<script src="myApp.js"></script>
<script src="myAppModels.js"></script>
<script src="myAppControllers.js"></script>
</body>
</html>
template_initialPageView.html
<div class="page-container" data-ng-cloak>
<!-- Table Content -->
<table class="table" data-ng-cloak>
<thead>
<tr><th colspan="{{keysToShow.length}}"><h1>People</h1></th></tr>
<tr><th data-ng-repeat="header in keysToShow">{{ header.displayName }}</th></tr>
</thead>
<tbody>
<tr data-ng-repeat="person in people | orderBy:orderProp">
<td><a href="#{{[person.firstName, person.lastName].join('_')}}"
data-ng-click="showModal(person)"
>{{ [person.firstName, person.lastName].join(' ') }}</a></td>
<td>{{ person.profession }}</td>
</tr>
</tbody>
</table>
</div>
template_modalContentView.html
<div class="modal-header">
<button type="button" class="close" data-ng-click="cancelModal()">×</button>
<h3 class="modal-title" id="myModalLabel">Person Info</h3>
</div>
<div class="modal-body">
<tabset>
<tab heading="Age">
<h4>Name</h4>
<p>{{ person.firstName + ' ' + person.lastName }}</p>
<h4>Age</h4>
<pre>{{ person.age }}</pre>
</tab>
<tab heading="Profession">
<h4>Name</h4>
<p>{{ person.firstName + ' ' + person.lastName }}</p>
<h4>Profession</h4>
<pre>{{ person.profession }}</pre>
</tab>
</tabset>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-ng-click="closeModal()">Close</button>
</div>
myApp.js
var myApp = angular.module('myApp', ['ui.bootstrap', 'ngRoute']);
/* Routes */
myApp.config(function($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: 'template_initialPageView.html',
controller: 'PageViewController',
controllerAs: 'page'
})
.otherwise({
redirectTo: '/home'
});
});
myAppControllers.js
var myAppControllers = {};
// Define: Page View Controller
myAppControllers.PageViewController = function ($scope, $modal, modelFactory) {
init();
function init(){
$scope.orderProp = '';
$scope.keysToShow = [{'displayName':'Fullname'},{'displayName':'Profession'}];
modelFactory.getPeople().success(function(data){
$scope.people = data;
});
}
$scope.showModal = function(person) {
console.log('person clicked', person);
$scope.person = person;
var modalInstance = $modal.open({
controller: 'ModalController',
controllerAs: 'modal',
templateUrl: 'template_modalContentView.html',
resolve: {
person: function(){
return $scope.person;
}
}
});
};
};
// Define: Modal Controller
myAppControllers.ModalController = function ($scope, $modalInstance, person) {
init();
function init(){
$scope.person = person;
}
$scope.cancelModal = function (){
$modalInstance.dismiss('cancel');
};
$scope.closeModal = function () {
$modalInstance.close();
};
};
// Add controlers to the module
myApp.controller(myAppControllers);
myAppModels.js
myApp.factory('modelFactory', function($http){
var factory = {};
factory.getPeople = function (){
return $http.get('data.json');
};
return factory;
});
You can try this, it initially returns an empty array that will be populated when $http.get() returns and it re-uses the array each time it is called:
myApp.factory('modelFactory', function($http){
var factory = {};
factory.getPeople = function () {
if (typeof(factory.people) == "undefined") {
factory.people = [];
$http.get('data.json').success(function(result) {
var i = 0;
for (i = 0; i < result.length; i++) {
factory.people.push(result[i]);
}
});
}
return factory.people;
};
return factory;
});
And don't forget to change your assignment to accept an array and just use that:
$scope.people = modelFactory.getPeople();
(PLUNKR)