What's the preferred way to handle routing after a controller is done performing a task? In my specific scenario, I have a route that goes to a "create a new record" page. On clicking the submit button, the controller does its thing. I know it's bad practice to directly do a $location.path() call from inside the controller, so what's the preferred way to tell my view to go to a new location?
View:
<section ng-controller="AssignmentController">
<h3>New Assignment</h1>
<form name="assignments_new">
<label for="description">Description</label> <input name="description" id="description" ng-model="assignment.description" type="text" ng-maxlength="100" placeholder="Short description of project" />
<button class="button button-mini button-primary" ng-click="createAssignment()">Create</button>
<button class="button button-mini" cancel>Cancel</button>
</form>
</section>
Controller:
$app.controller('AssignmentController', function($scope, $routeParams, $http) {
$scope.assignment = {
description: null
}
$scope.createAssignment = function() {
$http.post('/hooks/assignments_new.php', $scope.assignment).success(function(data) {
if (data.success) {
// Tell the view to redirect back to /assignments
} else {
}
}).error(function(data)) {
}
}
});
I have years of javascript experience, but this is my first go with Angular. Thanks for the help!
Related
im not sure the title explains clear enough what im trying to do, so im gonna try to explain here. i did the blog app from the book angularjs - from novice to ninja. because the api that the book uses is not working anymore, there were some functionalities i wasn't able to test. so later i did another tutorial of phalcon and build and api to do what the one in the angularjs book was supposed to. the api works fine (tested with postman, and also i use it for the login, so the blog app reaches it but i was only able to make it work in the login so far). so i have some doubts about the data i get from the api and how to show it in the for when i try to update one of the posts.
so the services.js file is like this:
angular.module('spBlogger.admin.services', []).
factory('Post', ['$resource', 'API_ENDPOINT', function ($resource, API_ENDPOINT) {
return $resource(API_ENDPOINT, {id:'#_id'}, {
update: {
method: 'PUT'
}
});
}]).
service('popupService', ['$window', function($window){
this.showPopup = function(message){
return $window.confirm(message); //Ask the users if they really want to delete the post entry
}
}]).
value('API_ENDPOINT', 'http://testing-phalcon/api/posts/:id');
the controller.js file:
controller('PostUpdateController', ['$scope', 'Post', '$stateParams', function ($scope, Post, $stateParams) {
console.log('in PostUpdateController');
$scope.post = Post.get({id:$stateParams.id}); //Obtain the Post from backend. Search by Id
console.log($scope.post);
$scope.buttonText = "Update"; // Set initial label for button
$scope.updatePost = function(){
$scope.buttonText = "Updating. . ."; //Once clicked change button text
$scope.post.$update(function(){
$state.go('admin.postViewAll'); //Once updated go to state 'admin.postViewAll'
});
}
}])
the admin-update-post.html file that loads the form:
<div class="row">
<div class="col-xs-8">
<form name="postForm" ng-submit="updatePost()" class="form-horizontal" novalidate role="form">
<div ng-include="'modules/admin/views/_form.html'"></div>
</form>
</div>
</div>
and finally the _form.html:
<div class="form-group" ng-class="{'has-error':postForm.title.$dirty && postForm.title.$invlaid}">
<label for="title" class="col-sm-2 control-label">Post Title</label>
<div class="col-sm-10">
<input type="text" name="title" ng-model="post.title" ng-required="true" class="form-control" id="title" placeholder="Title">
<span>Permalink:<i>/posts/[id]/{{post.title | permalink}}</i></span>
<span class="error-message" ng-show="postForm.title.$dirty && postForm.title.$invalid">Title is mandatory</span>
</div>
</div>
<div class="form-group" ng-class="{'has-error':postForm.content.$dirty && postForm.content.$invalid}">
<label for="content" class="col-sm-2 control-label">Content</label>
<div class="col-sm-10">
<textarea cols="8" rows="6" name="content" class="form-control" ng-model="post.content" ng-required="true" id="content" placeholder="Content"></textarea>
<span>{{post.content | wordcount}} words</span><br/>
<span class="error-message" ng-show="postForm.content.$dirty && postForm.content.$invalid">You need to have some content!</span>
</div>
</div>
<div class="form-group" ng-class="{'has-error':postForm.keywords.$dirty && postForm.keywords.$invalid}">
<label for="keywords" class="col-sm-2 control-label">Keywords</label>
<div class="col-sm-10">
<input type="text" name="keywords" class="form-control" id="keywords" ng-pattern="/^[\w,]+$/" ng-model="post.keywords" placeholder="Comma separated keywords" />
<span class="error-message" ng-show="postForm.keywords.$dirty && postForm.keywords.$invalid">Sorry! No special characters allowed here</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success" ng-disabled="postForm.$invalid">{{buttonText}}</button>
</div>
</div>
What i want to achieve is that when i select a post that i want to update, i want to display the form with the data from the post in the title input, the content in the textarea, and the keywords in the keywords input.
what i tried in the controller (forgive me if it looks bad, but im very new to angular) is:
$scope.thepost = {};
$scope.thepost.title = $scope.post.title;
but this obvioulsy doesn't work. i know the data is getting to the controller because of the console logs (i can see the api answers correctly), but im not sure first how to parse it and then how to pass it from the controller to the view. any help is welcome. thanks!
EDIT
the template that displays all the posts available is admin-all-posts.html:
<div class="row">
<div class="col-xs-8">
<table class="table">
<tr>
<td><h3>View All Posts</h3></td>
<td></td>
</tr>
<tr ng-repeat="post in posts | orderBy:'-_id'">
<td>{{post.title}}</td>
<td>
<a class="btn btn-primary" ui-sref="admin.postUpdate({id:post.id})">Edit</a>
<a class="btn btn-danger" ng-click="deletePost(post)">Delete</a>
</td>
</tr>
</table>
</div>
</div>
the controller that loads the posts from the api is in controllers.js:
controller('PostListController', ['$scope', 'Post', 'popupService', '$state', function ($scope, Post, popupService, $state) {
$scope.posts = Post.query(); //Obtain all the posts from backend
$scope.deletePost = function(post){
if(popupService.showPopup('Really delete this?')){ //Ask for confirmation
post.$delete(function(){
$state.go('admin.postViewAll', undefined, { //once deleted reload the state
reload: true
});
});
}
}
}])
i hope this helps
Examine the $scope.post after the data arrives from the server:
controller('PostUpdateController', ['$scope', 'Post', '$stateParams', function ($scope, Post, $stateParams) {
console.log('in PostUpdateController');
$scope.post = Post.get({id:$stateParams.id}); //Obtain the Post from backend. Search by Id
̶c̶o̶n̶s̶o̶l̶e̶.̶l̶o̶g̶(̶$̶s̶c̶o̶p̶e̶.̶p̶o̶s̶t̶)̶;̶
$scope.post.$promise.then(function() {
console.log($scope.post);
}).catch(function(error) {
console.log("ERROR:", error);
});
$scope.buttonText = "Update"; // Set initial label for button
$scope.updatePost = function(){
$scope.buttonText = "Updating. . ."; //Once clicked change button text
$scope.post.$update(function(){
$state.go('admin.postViewAll'); //Once updated go to state 'admin.postViewAll'
});
}
}])
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
Could someone please point out the mistakes in the code,
Problem 1 Save button of addstudent.html file is not working. If using $Scope then its working but have modified the code for using ControllerAs, the functionality stopped working. When checked in debugger tool even control is not comimg in addStudentController page at line
(addCtrl.saveStudent = function(student){)
on clicking save button and nothing is happening.
Problem 2 In app.js when ever the commented code become active, the application stopped working at all.
Problem 3 Want to know the way of redirecting to index.html at cancel button of addStudentController.js, using window.location is good practice?
addStudentController.js
module.controller('addStudentController',
function addStudentController(){
addCtrl = this;
addCtrl.saveStudent = function(student){
window.alert(student.name+' save successfully');
};
addCtrl.cancelStudent = function(){
window.location='/index';
};
}
);
app.js
var module = angular.module('myApp',['ngRoute'])
.config(['$routeProvider', function($routeProvider){
$routeProvider
/*.when('/index', {
templateUrl: 'index.html',
controller: 'studentController',
title: 'This is index page'
})*/
.when('/addStudent', {
templateUrl:'templates/addStudent.html',
controller:'addStudentController',
controllerAs: 'addCtrl'
})
/*.otherwise({
redirectTo: '/index'
})*/;
}]);
addStudent.html
<div>
<div>
<h1>New Student</h1>
<p>
<img data-ng-src="{{student.imageUrl}}" alt={{student.name}}
height="40px">
</p>
<hr>
<form name="newStudentForm">
<fieldset>
<label for="studentName">Student Name:</label>
<input id="studentName" type="text" data-ng-model="student.name" required
placeholder="Name of student...."> <br>
<label for="studentDepartment">Student Department:</label>
<input id="studentDepartment" type="text"
data-ng-model="student.department" placeholder="Name of student Department ...."> <br>
<label for="studentBranch">Student Branch:</label>
<input id="studentBranch" type="text" data-ng-model="student.branch"
placeholder="Name of student Branch ...."> <br>
</fieldset>
<button type="submit" data-ng-disabled="newStudentForm.$invalid"
data-ng-click="saveStudent(student)">Save</button>
<button type="button" data-ng-click="cancelStudent()">
Cancel</button>
</form>
<label for="studentImage">Student Image:</label> <input
id="studentImage" type="text" data-ng-model="student.imageUrl"
placeholder="url for student image ....">
</div>
</div>
Problem 1: Use addCtrl.saveStudent(student) in your html
Problem 2: Do you see an exception in the console? You might not have injected the controller correctly, or your template url could be wrong. Hard to tell with current info.
Problem 3: Use location service: Angular location
hope you guys are kicking and jumping. Thanks for your usual understanding.
Frameworks: AngularJS, NodeJS
I am designing a login page. But the data to be compared with is an array of items in testData.html. I want to call the data on the login.html and compare it with user's input.
The login form works properly but the data is not read. I tried compiling the dataobject.html file separately, and it did not run.
I do not want to store this data in a .json file.
Later I will learn how to use the MongoDB to read data and compare
Please check the codes below.
[LOGIN.HTML]
<div ng-app="myApp" ng-controller="loginCtrls" style="height:auto;">
<form name="lForm">
<div class="container">
<label><b>Username</b></label>
<input class="w3-round" type="text" name="username" placeholder="Username" ng-model="username" required>
<div align="right" style="width:550px;">
<span style="color:red" ng-show="lForm.username.$dirty && lForm.username.$invalid">
<span ng-show = "lForm.username.$error.required">Username is required.</span>
</span>
</div>
<label><b>Password</b></label>
<input class="w3-round" type="password" name="password" ng-model="password" placeholder="Password" required>
<div align="right" style="width:550px;">
<span style="color:red" ng-show="lForm.password.$dirty && lForm.password.$invalid">
<span ng-show = "lForm.password.$error.required">Password is required.</span>
</span>
</div>
<div align="center">
<button class="w3-btn w3-teal w3-round" style="height:45px; width:100%; font-size:16px;" ng-disabled = "lForm.username.$dirty && lForm.username.$invalid || lForm.password.$dirty && lForm.password.$invalid" ng-click="chkData()">Click to Login</button>
</div>
<input type="checkbox" checked="checked"> Remember me
</div>
<div class="container" style="background-color:#f1f1f1; margin-top:0;">
<span>Forgot password?</span>
</div>
</form>
<h4>{{result}} login attempt</h4>
</div>
<script src="js/loginCtrl.js"></script>
[LOGINCTRL.JS]
// JavaScript Document
var app = angular.module('myApp', []);
app.controller('loginCtrls', function($scope, $http) {
//get the file from the dataobject.html file
$http.get("dataobject.html").then(function (response) {
//parse the array object to $scope.users
$scope.users = response.data.records;
});
//this function checks the user's input and
//compares it with the any match in object array
//the object array data has been passed into $scope.users
$scope.chkData = function(){
$scope.users = $scope.data.records;
angular.forEach($scope.users, function(value, key){
if(angular.equals(value.Username, $scope.username) && (value.Password, $scope.password)){
$scope.result = "Successful ";//msg to be displayed
}else {
$scope.result = "Unsuccessful ";//msg to be displayed
}
});
}
});
[DATA OBJECT.HTML]
<script src = "js/angular.min.js" type="text/javascript"></script>
<div ng-app="myApp" ng-controller="mdata">
</div>
<script>
var app = angular.module('myApp', []);
app.controller('mdata', function($scope) {
$scope.data =
{ "records":[ {"Username":"Alfreds","Password":"alfred","Session ID":"1"}, {"Username":"Ana","Password":"ana","Session ID":"2"}, {"Username":"Moreno","Password":"moreno","Session ID":"3"}] };
});
});
</script>
I would recommend to do it using a service. Angular services are singletons. So, from one controller, you put the data in a service, switch pages, get the data from the service.
NOTE: if user refreshes the page, the data in the service will be lost, as services (or angular for that matter) does not persist state.
ofc, everyone will have their own solution. I see you are a beginner, so the answer is meant to help you get a grasp of angular.
You can store your data either on the $rootScope or by creating localStorage Services and u can access data anywhere in application but the best practices are creating some localStorage services.
Is there a way to access $route from the html side of AngularJS?
I'd really like to do something like this in HTML and eliminate yet another $scope function. (yes, i know its not really something that works):
<button ng-disabled="!route.current.scope.currentform.$valid">
I am working on a large angular application that is somewhat 'down the road' in the development cycle. At this time we have decided to implement form validation (don't ask why it wasn't 1 or 2 on the list).
I am currently using two buttons in the footer "previous" and "next", both which need to ng-disabled set to !$scope.formname.$valid. This needs to work across multiple controllers / pages, since the buttons are in my footer on index.html.
The code i'm using right now looks like this:
// Want to eliminate this isFormValid() method
$scope.isFormValid = function() {
if ($route.current) {
if ($route.current.scope) {
return !$route.current.scope.currentform.$valid;
}
}
};
$scope.prevPage = function() {
if (angular.isFunction($route.current.scope.PrevAction)) {
// do stuff particular to the current controller
$route.current.scope.PrevAction()
}
};
$scope.nextPage = function() {
if (angular.isFunction($route.current.scope.NextAction)) {
// do stuff particular to the current controller
$route.current.scope.NextAction()
}
};
and the corresponding button code is as follows:
<div class="footer">
<button id="main-prev-button" type="button" class="btn btn-primary previous" ng-click="prevPage($event)" ng-disabled="isFormValid()">Previous</button>
<button id="main-next-button" type="button" class="btn btn-primary next" ng-click="nextPage($event)" ng-disabled="isFormValid()">Next</button>
</div>
Each page code looks something like this
<ng-form id="currentform" name="currentform">
<label>Full Name</label>
<input type="text" class="form-control" ng-model="nl.firstName" id="firstName" placeholder="First Name" name="firstName" ng-minlength="5" ng-maxlength="20" ng-required="true">
<pre>currentform.firstName.$error = {{ currentform.firstName.$error | json }}</pre>
<ng-messages for="currentform.firstName.$error">
<ng-message when="required">You did not enter a field</ng-message>
<ng-message when="minlength">Your field is too short</ng-message>
<ng-message when="maxlength">Your field is too long</ng-message>
</ng-messages>
</ng-form>
Add the $route to the root scope $rootScope and then access it in your html/view using the $rootScope.$route.
E.g:
angular.module('myApp').run(['$rootScope', '$route',
function ($rootScope, $route) {
$rootScope.$route = $route;
}]);
I'm a newbie to Angular JS. I've created a form in my index.html page, when I fill the details in the form and press submit, it should redirect to details.html page. Where I can able to show the details filled on the form.
HTML
<html>
<script src="angular.min.js"> </script>
<script src="script.js"> </script>
</head>
<body ng-app="FormApp">
<div class="forms" ng-controller="CustomerDetailsController">
<form novalidate>
First Name:<br>
<input type="text" ng-model="firstName" required/>
<br>
<br>
Last Name:<br>
<input type="text" ng-model="lastName">
<br>
<br>
Age:<br>
<input type="text" ng-model="lastName">
<br>
<br>
Email :<br>
<input type="email" ng-model="lastName">
<br>
<br>
Location<br>
<input type="text" ng-model="lastName">
<br>
<br>
<button ng-click="submit()">SUBMIT</button>
</form>
</div>
</body>
</html>
CONTROLLER
var FormApp = angular.module('FormApp', []);
FormApp.controller('CustomerDetailsController', ['$scope',function($scope) {
$scope.submit = function() {
}
}]);
What will be the best way to do this? Any help would appreciated, Thanks.
You can achieve this by adding angular routing to your application which need ngRoute dependency. Then you need to define one parent controller that can hold the partial views common data like here it is mainCtrl.
Apart from that you missed few things while you created a form, form should have its name attribute so that angular will create a scope variable of that form and internally manages form validity inside that scope variable like $valid, $error, etc. Then the same name should be given to each form element, if you don't declare the name attribute, then it won't consider it as form element.
HTML
<html ng-app="app">
<head>
<script type="text/javascript" src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script type="text/javascript" src="http://code.angularjs.org/1.2.13/angular-route.js"></script>
<script src="example.js"></script>
</head>
<body>
<div ng-controller="mainCtrl">
<div class="forms">
<ng-view></ng-view>
</div>
</div>
</body>
</html>
CODE
var app = angular.module('app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl: 'view1.html',
controller: 'CustomerDetailsController'
})
.when('/view2', {
templateUrl: 'view2.html',
controller: 'form2Ctrl'
})
.otherwise({
redirectTo: '/view1'
});
});
app.controller('mainCtrl', function($scope) {
$scope.form = {};
});
app.controller('CustomerDetailsController', function($scope,$location) {
$scope.submit = function(){
if($scope.form1.$valid)
$location.path('/view2');
};
});
app.controller('form2Ctrl', function($scope,$location) {
//this controller contain the data which will you get from
});
Working Plunkr
Update
Clearing confusion of on what form2Ctrl will contain as per request by #user3440121.
The second view may contain a ajax call that will fetch the user information from server and display it on the view or it can be any show the list of employees, Its depend on the whats the requirement of your application.
Basically you should not store data on client side as i did stored the data in form object and accessing it on view2 directly as I can access parent scope variable. I shown this only for demonstration purpose. In actual implementation we will take $route parameter from the URL & the we will make an ajax call to server which give data back to you. Currently in plunkr we redirecting to view2 using $location.path('/view2'); that would change to $location.path('/edit/1') and you need to add route to your app.config like
Route
.when('/edit/:id', {
templateUrl: 'view2.html',
controller: 'form2Ctrl'
})
Controller
app.controller('form2Ctrl', function($scope,$route) {
//we can get id here from $route object
console.log($route.params.id); //here it will be `id` which `1` in the URL
//now you have id you can make ajax to server and get required data
});
Hope above information cleared all the doubts about the question. Thanks.
Your $scope.submit function has nothing inside it for routing.
It should be:
$scope.submit = function($scope) {
$scope.$apply(function() {
$location.path("*place your details page here*");
});
}
Note that you also need to inject $location to your controller, as follows:
FormApp.controller('CustomerDetailsController',
['$scope', '$location', function($scope, $location) ...
Try reading the following for more details:
https://docs.angularjs.org/api/ng/service/$location
Also have you tried checking your paths? (e.g. angular.min.js, script.js)