$location.path does not change the route after form submit - javascript

I have seen many issues regarding the $location.path in angular js on stackoverflow but none of them would solve the issue I have.
I have defined below routes in my app.js:
angular.module(
'hotPosts',
[ 'hotPosts.filters', 'hotPosts.services',
'hotPosts.directives',
'hotPosts.controllers', 'ngRoute', 'ngSanitize' ]).config(
[ '$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider.when('/hot-posts', {
templateUrl : 'gptarin/partials/hot-posts.jsp',
controller : 'ListPostsCtrl'
});
$routeProvider.when('/list-users', {
templateUrl : 'gptarin/partials/list-users.jsp',
controller : 'ListUserCtrl'
});
$routeProvider.when('/edit-user/:userId', {
templateUrl : 'gptarin/partials/edit-user.jsp',
controller : 'EditUserCtrl'
});
$routeProvider.when('/create-user', {
templateUrl : 'gptarin/partials/edit-user.jsp',
controller : 'EditUserCtrl'
});
$routeProvider.otherwise({
redirectTo : '/hot-posts'
});
$locationProvider.html5Mode(false);
} ]);
The list-users.jsp partial will show a list of users where I can select a record to update. When I click ong update button the ngRoute successfully routes the app to edit-user.jsp partial. However, when I click the Save button in that page, it does not change the route to "/list-users", even though I used the $location.path('/list-users') in Controller EditUserCtrl. It redirects me to "[app_url]/?".
Here is my controllers:
app.controller('EditUserCtrl', [
'$scope',
'$routeParams',
'UserListFactory',
'UserFactory',
'$location',
function($scope, $routeParams, UserListFactory, UserFactory,
$location) {
// callback for ng-click 'updateUser':
// force it to refresh in the client
$scope.saveUser = function() {
if (angular.isUndefinedOrNull($scope.user)) {
$scope.user = {};
UserListFactory.create($scope.user, function() {
$location.path('/list-users');
});
} else if (angular.isUndefinedOrNull($scope.user.id)) {
UserListFactory.create($scope.user, function() {
$location.path('/list-users');
});
} else {
UserFactory.update($scope.user, function() {
$location.path('/list-users');
});
}
};
// callback for ng-click 'cancel':
$scope.cancel = function() {
$location.path('/list-users');
};
if ($routeParams.userId !== undefined) {
$scope.user = UserFactory.show({
userId : $routeParams.userId
});
}
} ]);
The update function (saveUser) uses a service which makes Restful requests to the backend server via ngResource. The service works fine (all tests are passed).
I have enclosed the $location.path in the success callback function when calling the resource actions.
I have tried catching "$locationChangeSuccess" and "$locationChangeError" and saw that in this case a $locationChangeError is thrown but I do not know which promise object is rejected causing this error.
Any help is highly appreciated.
Edit:
Here is the edit-user.jsp partial
<div class="container-fluid">
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title label">Edit User</h2>
</div>
<div class="panel-body">
<form role="form" action="#" class="form-horizontal" ng-submit="saveUser()">
<div class="form-group col-sm-11">
<div class="form-group">
<label for="accountId" class="col-sm-1 control-label">G+
Id: </label>
<div class="col-sm-4">
<input type="text" id="accountId" class="form-control"
ng-model="user.gpId"></input>
</div>
<label for="accountName" class="col-sm-2 control-label">Name:
</label>
<div class="col-sm-5">
<input type="text" id="accountName" class="form-control"
ng-model="user.name"></input>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="checkbox" id="showPosts" class="form-control"
ng-model="user.listPosts">ShowPosts</input>
</div>
</div>
</div>
<div class="form-group col-sm-1">
<div class="row">
<div class="col-sm-offset-1 col-sm-12 pull-right">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
<div class="row">
<div class="col-sm-offset-1 col-sm-12 pull-right">
<button type="button" class="btn btn-primary" ng-click="cancel()">Cancel</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

Well After a few days of trying everything and not finding any help over internet I sort of fixed this issue.
I decided to share it with whoever reads this post so that it does not take several days of them as well.
When I traced my app more carefully I figured out that my cancel button worked just fine and $location.path was successfully sending me back to the /list-users page.
Further investigations showed that the difference between my Cancel and Save buttons was that the Cancel button uses the ng-click whereas I defined the type of my Save button to be "submit".
I then changed my html code so that instead of providing the function call saveUser() in ng-submit of the form, I used an ng-click for the Save button and changed its type to "button".
Here is the working version of my html partial. I did not need to change anything in js files.
<form role="form" action="#" class="form-horizontal">
<!-- ng-submit="saveUser()"> -->
<div class="form-group col-sm-11">
<div class="form-group">
<label for="accountId" class="col-sm-1 control-label">G+ Id: </label>
<div class="col-sm-4">
<input type="text" id="accountId" class="form-control" ng-model="user.gpId"></input>
</div>
<label for="accountName" class="col-sm-2 control-label">Name: </label>
<div class="col-sm-5">
<input type="text" id="accountName" class="form-control" ng-model="user.name"></input>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<label>
<input type="checkbox" id="showPosts" ng-model="user.listPosts"> Show Posts
</label>
</div>
<div class="col-sm-12">
<button type="button" class="btn btn-primary" ng-click="saveUser()">Save</button>
<button type="button" class="btn btn-primary" ng-click="cancel()">Cancel</button>
</div>
</div>
</div>
</form>
I still still do not now the mechanics of form submit in angular and why it causes one of the promise objects that the $location.path expects to fail (and hence causing an error in routing).
Any clarifying comment in this regard is much appreciated.

Well after more than a year of experience with Angular, I now know what was the problem in the first instance.
Reading Angular's documentation for ng-submit I found out this:
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page), but only if the form does not contain action, data-action, or x-action attributes.
Looking at the code it is evident that I mistakenly added an action attribute when I was defining the form element:
<form role="form" action="#" class="form-horizontal" ng-submit="saveUser()">
Removing it will fix the problem:
<form role="form" class="form-horizontal" ng-submit="saveUser()">

you can add $event.preventDefault(); before saveUser(); it will works.

Related

AngularJS show data from api in form to update it

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.

AngularJS - Proven way of handling ng-model data

I have a form, and I'm trying to bind date from it in the angularjs - controller so I can pass it into the djangorestframework view to do more stuff with it.
Now my problem is that I don't understand how to properly bind data from the datetimepicker input filed in the controller, I'll show up my form and small part of the controller, as far as I understand this is that I need to have ng-model on the input field and put a function on the Submit button, and that is clear for me but the part in the controller I don't understand, so how can I properly bind this, can someone please help me, thank you, controller is written in coffee script.
<div class="flex-grid"
ng-controller="FilterContactsListCtrl">
<div class="row">
<div class="cell size-p20 padding10">
<form action="." method="post">{% csrf_token %}
<label for="id_select_date">Select Date: *</label>
<div class="full-size">
<div class="input-control full-size text"
data-role="datepicker" date-format="mmmm d, yyyy">
<input id="id_select_date" ng-model="selectDate"/>
<button class="button"><span class="mif-calendar"></span></button>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="cell size-p20 padding10">
<button class="button primary" ng-click="doAction()">
{% trans "Submit" %}
</button>
</div>
</div>
</div>
Controller:
app = angular.module 'vinclucms.sales'
app.controller 'FilterContactsListCtrl', ['$scope', '$rootScope', 'LeadContact'
($scope, $rootScope, LeadContact) ->
$scope.doAction = ()->
filterLeadContactList()
filterLeadContactList = () ->
$scope.selectDate = null
$scope.doAction = () ->
# Do Action with date form the input field so I can pass it to the restapi view
# this part I don't understand, how to bind this properly
]
the problem is you don't pass any model to your controller. basicly your doAction() method can't do anything!
What I suggest is to change your form to use ng-submit and pass your model to controller.
<form ng-submit="doAction(selectDate)" action="." method="post">{% csrf_token %}
<label for="id_select_date">Select Date: *</label>
<div class="full-size">
<div class="input-control full-size text"
data-role="datepicker" date-format="mmmm d, yyyy">
<input id="id_select_date" ng-model="selectDate"/>
<button class="button"><span class="mif-calendar"></span></button>
</div>
</div>
<button class="button primary" type="submit">
{% trans "Submit" %}
</button>
</form>
As you notice I bring your button inside the form with type=submit.
Later in your controller you can access your data model like this :
$scope.doAction = function(selectDate){
console.log(selectDate); // You have access to your data now
//Do what ever you want
}

AngularJS: Using ControllerAs in router not working and Issue with app.js

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

Incorporate directive's functionality into Angular form validation

I have two questions that are related:
First: I have the following directive, who's purpose is to validate whether an input[type=file] is valid or not, however I have no idea how it does it least of all, what the actual code means, here it is:
angular.module('sccateringApp')
.directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Like I said, I have no idea what the above code actually does, the explanation I got from the forum where I copied that was that it validated an input type file. Is this correct? (So far I haven't been able to verify if it works or not since it doesn't work with the code I'm using at the moment to validate my forms).
Second: Having the form below, using angular form validation it doesn't allow the submit button to be clicked until the actual inputs inside the form match the validation rules (enter a name for the category, and the description should have a max length of 144 characters). I included the directive into the file input, however the actual ng-model for the form ignores the required in the input type file and just verifies the rules are met for the first two inputs.
Here is my form:
<form method="post" role="form" name="newCategoryForm" ng-submit="submitForm()" enctype="multipart/form-data" novalidate>
<div class="row">
<div class="row">
<div class="col s12">
<div input-field>
<input type="text" name="cat-name" id="cat-name" ng-class="{ 'ng-invalid' : newCategoryForm.catname.$invalid && !newCategoryForm.catname.$pristine }"
ng-model="catname" required>
<label>Nombre</label>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<div input-field>
<textarea class="materialize-textarea" name="cat-description" id="cat-description" length="144"
ng-model="catdescription" ng-maxlength="144" required></textarea>
<label>Descripción</label>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<h6>Imagen de Fondo</h6>
<div class="file-field input-field">
<div class="btn pink darken-2 waves-effect waves-light">
<span>Archivo</span>
<input type="file" name="cat-bgimg" id="cat-bgimg"
file-model="variable" required>
</div>
<div class="file-path-wrapper">
<input class="file-path" type="text">
</div>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-large pink darken-2 waves-effect waves-light center-button" ng-disabled="newCategoryForm.$invalid">Crear Categoría</button>
</form>
The first two inputs get validated correctly, the third one (file input) doesn't and I don't really know why since the directive got included on the input (I know natively, ngModel doesn't validate file inputs).
Any ideas or suggestions of how can I fix this? I'm really new to Angular, and all the tutorials are pretty much useless. I come from 5 years of experience working on jQuery, and the transition to Angular hasn't been easy at all.
The directive posted above is used to make the submit get the data found in the <input type="file"></input>.
Also, a variable should be initialized in the controller so that the values found inside the form are copied to said variable, then this variable needs to be sent as a parameter inside the ng-submit="submitForm().
Example:
angular.module('sccateringApp')
.controller('newSubcategoryController', function (httpcalls, $scope) {
...
$scope.subcategory = [];
...
$scope.submitForm = function(subcategory){
...
$scope.request.insertSubcategory(subcategory);
}
});
Each ng-model inside the form would be:
<input type="text" ng-model="category.name">
So that the category variable found in the controller acquires that value.

controller method never called?

I am new in AngularJS, I want to call signup method on button ng-click, but it never gets called.
<div class="row">
<div class="col-sm-5" style="" ng-controller="SignUpController">
<div class="row">
<button ng-click="$parent.signup()" class="form-control btn btn-primary">Sign-Up</button>
</div>
</div>
Angular Script
<script>
angular.module('index',[])
.controller('SignUpController', ['$scope', function($scope) {
$scope.signup=function(){
alert("");
};
}]);
</script>
Try this
<button ng-click="signup()" class="form-control btn btn-primary">Sign-Up</button>
in your case $parent does not have method signup

Categories