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.
Related
I am trying to auto post a form from a controller without any user interaction on the form. I have a private init() function in the controller that triggers a button click on the form.
But the hidden form fields did not get the values yet. How can I make sure the hidden fields will have values populated before the form submits?
Thank you for any suggestions.
<div>
<form name="myForm" method="post" action="#Model.Settings["URL"]" ng-controller="MyCtrl">
<input type="hidden" name="userid" value="{{UserSettings.Settings.UserId}}">
<input type="hidden" name="amount" value="{{Payment.Amount}}">
<button id="payButton" type="submit" class="action blue"><span class="label">Pay</span></button>
<script language="javascript">
var UserSettings = (function (o) {
return o;
})(#Html.Raw(JsonConvert.SerializeObject(#Model)));
</script>
</form>
</div>
myControllers.controller('MyCtrl', ['$scope', '$state', '$element', 'dataService',
function ($scope, $state, $element, service) {
$scope.Payment = service.GetPayment());
$scope.UserSettings = UserSettings;
function init() {
// How can I force to have values in the hidden form fields before the button click that submits the form ?
$element.find('#payButton').trigger("click");
};
init();
}]);
Here is the ui-router states configuration.
var app = angular.module('pay', ['ui.router', 'pay.controllers', 'pay.services', 'exceptionOverride', 'ngSanitize']);
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function ($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: '/' ,
templateUrl: 'search'
})
.state('payment', {
url: '/payment',
templateUrl: 'Payment'
});
//setting html5 removes the # from URL but causes routing problems at the moment.
//$locationProvider.html5Mode(true);
$urlRouterProvider.rule(function ($injector, $location) {
//what this function returns will be set as the $location.url
var path = $location.path(), normalized = path.toLowerCase();
if (path != normalized) {
$location.replace().path(normalized);
}
else if (path == '') {
$location.path('/');
}
});
}]);
You can put the populations in the point you define the state which has MyCtrl as follows:
.state('myState', {
// ...
resolve: {
Payment: ['dataService', function (dataService) {
return dataService.GetPayment();
}],
// Same for other objects needed
}
})
And then in your Controller:
myControllers.controller('MyCtrl', ['$scope', '$state', '$element', 'Payment',
function ($scope, $state, $element, Payment) {
$scope.Payment = Payment;
// Same for other objects needed
// Rest code
}
The code in the Controller would not start running before all actions and promises in the resolve section finish.
Update:
You can put init call inside a $timeout.
$timeout(function(){
init();
});
Of course, you have to inject $timeout in Controller function along with the other dependencies.
Hi iam using Angular with Require.
Require is managing my dependency sequence. Using lazy loading for loading controller and i was able to load my first home controller but when i wanted to navigate to dashboard controller then iam getting error dashboard controller is not found. hereis code
main.html
<body ng-app >
<div id="ViewPort" ng-view> </div>
</body>
shell.js
define(['mngRoute', 'mngSanitize'], function (ngRoute, ngSantize) {
var CMSapp = angular.module('CMS', ['ngRoute', 'ngSanitize']);
CMSapp.config(function ($routeProvider, $httpProvider) {
console.log($httpProvider);
$routeProvider
// route for the home page
.when('/', { templateUrl: 'App/Partials/home.html', resolve: loader(['Home']) })
.when('/Dashboard', { templateUrl: 'App/Partials/Dashboard.html', resolve: loader(['Dashboard']) })
});
CMSapp.run(function () {
console.log('shell loaded');
console.log(CMSapp);
});
return CMSapp;
Home Controller.js
define(function () {
angular.module('CMS').controller('HomeController', ["$scope", "$http", 'MainService', function ($scope, $http, mainService) {
$scope.message = 'Homess';
$scope.InitializeController = function ()
{
console.log(mainService);
mainService.initializeApplication($scope.initializeApplicationComplete, $scope.initializeApplicationError);
}
$scope.initializeApplicationComplete = function (response) {
console.log('in default initializeApplicationComplete');
}
$scope.initializeApplicationError = function (response) {
console.log('in default intialize error');
}
}]);
});
Home.html
<div data-ng-controller="HomeController" ng-init="InitializeController()">
<span>{{message}}</span>
Dashboardcontroller and dashboard.html are same only difference is the name
define(function () {
angular.module('CMS').controller('DashboardController', ["$scope", "$http", 'MainService', function ($scope, $http, mainService) {
$scope.message = 'Dashboard';
$scope.InitializeController = function ()
{
console.log(mainService);
}
}]);
});
Dasboard html
<div data-ng-controller="DashboardController" ng-init="InitializeController()">
<span>{{message}}</span>
i was able to load home and able to bind with model, but this not in dashboard when i entered localhost:8999/Main.html#/Dashboard in url it gives error.
See the chrome console Full console
Angular, Route, Dasboardcontroller.js homecontroller.js shell.js are loaded successfuly no error in console only error is Dasboard controller is not a function, got defined
When you use ng-app, Angular will search for a module called app. If you want to specify a custom module, you need to tell it: ng-app="CMS"
I hope this works! :)
<body ng-app >
should be
<body ng-app="CMS">
because in your code you declare your module as so.
angular.module('CMS'
Chrome console image console2
You can see my app is loaded bootstrapped and controllers are registered as well
I have an index page wherein I define two controllers. I want to call one main controller always (should be rendered always) and the other is called only for specific sub URL calls. Should I make one nested within another, or I can keep them independent of each other? I don't have access to change routes or anything, only the controller.
Right now when I use the template (HTML) mentioned, it calls/renders both controllers, even though url is say /index
Only for /index/subPage, I want both controllers to be rendering.
/index
/index/subPage
HTML:
<div ng-controller="MainCtl" ng-init=initMain()>
<p> Within ctller2 {{results}} </p>
</div>
<div ng-controller="Ctller2"> <!-- should not be displayed unless /subPage/mainUrl is rendering -->
<p> Within ctller2 {{results}} </p>
</div>
JS:
app.controller('MainCtl', ['$scope', '$http', '$location', function ($scope, $http, $location) {
$http.get('xx/mainUrl').then(function(data) {
$scope.results = someDataJSON;
console.log(someDataJSON);
});
$scope.initMain = function() {
$scope.initMethods();
}
}]);
app.controller('Ctller2', ['$scope', '$http', '$location', function ($scope, $http, $location) {
// This controller gets initialized/rendered/called even when xx/mainUrl is called, and when xx/subPage/mainUrl is called too..
$http.get('xx/subPage/mainUrl').then(function(data) {
$scope.results = someDataJSON;
console.log(someDataJSON);
})
$http.get('xx/subPage').then(function(data) {
$scope.results = data.data;
console.log(data);
})
angular.element(document).ready(function () {
alert('Hello from SubCtl, moving over from main controller to here');
});
}]);
What am I doing wrong? I'm new to Angular.js
You can conditionally initiate a controller using ng-if. So you could try something like this:
<body ng-controller="MainCtrl">
<div ng-controller="ctrl1">{{hello}}</div>
<div ng-controller="ctrl2" ng-if="showCtrl2">{{hello}}</div>
</body>
and then set the value of the variable in a parent controller by checking the current url using $location.path()
var app = angular.module('plunker', []);
app.config(function($locationProvider){
$locationProvider.html5Mode(true);
});
app.controller('MainCtrl', function($scope, $location) {
$scope.showCtrl2 = ($location.path() === 'my path');
});
app.controller('ctrl1', function($scope){
$scope.hello = 'ctrl1 says hello';
});
app.controller('ctrl2', function($scope){
$scope.hello = 'ctrl2 says hello';
});
But it's a bit hacky and for a larger project a more robust solution would require using something like ui.router.
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.
I created an Angular app that uses Bootstrap. I based the project on a template that I downloaded and studied. I downloaded it from here: https://angularstart.codeplex.com
I did not use or modify the template to create the project that I have now. Instead, I created a new project and used Nuget to download the latest packages for Angular & Bootstrap.
The problem is in my 'Contact' page, which has a form for site visitors to send me a message. I have defined a function - sendMessage - inside the controller which is bound by ng-click to a button in the HTML.
appRoot.controller('ContactController', ['$scope', '$http', function ($scope, $http) {
$scope.contactModel = {};
$scope.sendMessage = function () {
alert('msg: ' + $scope.contactModel.msgSubject);
}
}]);
<input type="text" id="msgSubject" name="msgSubject" data-ng-model="contactModel.msgSubject" />
<button class="btn btn-primary" ng-click="sendMessage()" >Send Message</button>
The button and click event works fine but inside the function, it cant access the model variable. It returns with an 'undefined' - the alert says "msg: undefined"
I've researched this for three days now. I've looked at other demo code on plunkr and jsfiddle and I've seen it work but something in my setup prevents access to the scope variables (basically my defined model vars).
My angular app.js is:
var appRoot = angular.module('main', ['ngRoute', 'ngResource']);
appRoot
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', { templateUrl: '/main/home', controller: 'HomeController' })
.when('/home', { templateUrl: '/main/home', controller: 'HomeController' })
.when('/contact', { templateUrl: '/main/contact', controller: 'ContactController' })
}])
.controller('RootController', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (e, current, previous) {
$scope.activeViewPath = $location.path();
});
}]);
I've tested adding the variable when initializing the contactModel variable:
$scope.contactModel = { msgSubject: 'tst sub' };
The alert inside the 'sendMessage' function sees this and shows "msg: tst sub" correctly.
I've tried different configurations for the ContactController, including passing $location and $resource like so:
appRoot.controller('ContactController', function ($scope, $location, $resource) {
}
but still can't access the scope variables.
In all the samples & demos I've checked out - including the Angular Start tempate - the controller can access the defined ng-model variable. Makes me think it has to be in my configuration or use of the differnt versions of either Angular or Bootstrap.
My _Layout.cshtml defines the default controller and ng-app as so:
<body data-ng-app="main" data-ng-controller="RootController"style="background-color:transparent;" >
Angular version is v1.2.2 and Bootstrap is v3.1.0
Any help is apporeciated. Thanks
I think I've narrowed it down. I'd like to add that I am also using ASP.NET MVC with Razor.
If I put the HTML code outside the #RenderBody() and I put the javascript alert inside the RootController, the code works:
<div >
<div>
<input type="text" id="msgSubject" name="msgSubject" data-ng-model="contactModel.msgSubject" />
<button class="btn btn-primary" ng-click="sendMessage()" >Send Message</button>
</div>
</div>
<div >
#RenderBody()
</div>
And the Javascript:
app.controller('RootController', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (e, current, previous) {
$scope.activeViewPath = $location.path();
});
$scope.contactModel = {};
$scope.sendMessage = function () {
alert('msg: ' + $scope.contactModel.msgSubject);
}
}]);
If the HTML is inside the partial view (cshtml), the Angular controller does not see the scope variable as defined by ng-model.
Perhaps Angular execution is blocked by ASP.NET MVC's Razor engine? Something's going on in the #RenderBody() that is probably stripping the functionality out..