The full source code.
I don't understand why $scope not working in my LoginGuideCtrl controller. I try click on login button and should show a <p> with new data but the $scope is not updating...
Don´t forget I'm trying to achieve a modular design.
I have the following code:
guides.js
var guides = angular.module('main.guides', ['ui.router']).config(function ($stateProvider) {
$stateProvider.
state('guides.login', {
url: '/login',
templateUrl: 'modules/guides/views/login.html',
controller: 'LoginGuideCtrl'
}).
...
state('guides.mobile', {
url: '/web',
template: '<div>guildes mobile</div>',
controller: 'ListCtrl'
});
});
controller.js
var guides = angular.module('main.guides');
guides.controller('IndexCtrl', function() {
console.log('Index');
})
.controller('LoginGuideCtrl', function($scope) {
console.log('feck');
$scope.checkLogin = function(){
$scope.message = "Welcome "+$scope.name+"!"
};
})
.controller('ListCtrl', function() {
console.log('List');
})
login.html
<div class="form-group col-sm-2">
<label for="usr">Name:</label>
<input type="text" class="form-control" id="usr" ng-model="name">
</div>
<div class="form-group col-sm-2">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" ng-model="password">
</div>
<button type="button" class="btn btn-default" ng-click="checkLogin()">Login</button>
<p ng-model="message"></p>
ng-model is used with <input> tags to capture user input, by two way binding with your model value.
Since a <p> tag does not collect user input, it won't work with ng-model. Instead just do a one way binding with the value using the curly brackets:
<p>{{message}}</p>
Related
I have a multi step angular form using ui.router. I have a form html file that loads each step as a view. Each step has a button with a ui-sref link that takes the user to the next step. However it wont show the html 5 validation hints unless I remove the ui-sref. How can I have the validation work while still triggering the ui-sref at the same time?
my main form view:
<form ng-submit="processForm()" name="mortgage">
<div class="row">
<!-- our nested state views will be injected here -->
<div id="form-views" class="small-12 columns" ui-view></div>
</div>
</form>
my view html:
<h3>Please provide some information about your property</h3>
<label for="name">Zip Code</label>
<input type="text" pattern="[0-9]{5}" class="form-control" name="zipcode" type="number" ng-model="formData.zipcode" placeholder="Zip Code" required>
<button ui-sref="form.verify" type="submit" class="next">Next</button>
my controller
angular
.module('angularApp', [
'rzModule',
'btford.modal'
'ui.router'
])
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/form/property-type');
$stateProvider
.state('form', {
url: '/form',
templateUrl: 'views/form.html',
controller: 'FormCtrl'
})
.state('form.info', {
url: '/property-info',
templateUrl: 'views/property-info.html'
})
.state('form.verify', {
url: '/property-verify',
templateUrl: 'views/property-verify.html'
})
.controller('FormCtrl', function($scope) {
$scope.formData = {};
$scope.processForm = function() {
console.log($scope.formData);
};
});
I am trying to write a post request to log in a user and nothing works. I can't see why and would be happy about any help! Thanks!!
My controller:
'use strict';
app.controller('loginController', function($scope, $state, $http){
$scope.submitLogin=function(email,password)
return $http.post('/login', {email:$scope.email, password:$scope.password })
//since i have ng-model="email"- I don't actually need to pass in $scope.email but can pass in only email ?!
.then(function(success){
if (sucess){
console.log(success)
$state.go('stories')
}
else {
console.log('error')
}
})
.catch(function(err){
console.log("bad")
})
})
Part of the HTML:
<div class="form-group">
<label ng-model="email">email</label>
<input type="text" class="form-control" required />
</div>
<div class="form-group">
<label ng-model="password">password</label>
<input type="password" class="form-control" required />
</div>
<button type="submit" class="btn btn-block btn-primary" ng-click="submitLogin()">login</button>
</form>
State:
'use strict';
app.config(function ($stateProvider) {
$stateProvider.state('login', {
url: '/login',
controller:'loginController',
templateUrl: '/browser/app/login/login.html'
});
});
Put ng-model in input tag.
$scope.submitlogin=function(){
data={
email:$scope.email,
password:$scope.password
}
$http.post('/login',data).success(function(){
});
}
try in this way.It might work.
I wrote a basic login form in this plunk http://plnkr.co/edit/xQEN1ZNN5ZEw1CSwNw97?p=preview (click on the red Log into Dashboard button on the Home route).
However for some reason I cannot get the login() method to fire in my loginCtrl controller code.
Why is this example working, and mine is not ? http://plnkr.co/edit/H4SVl6?p=preview
Instead what it's doing is an old-school URL redirect with the user/password parameters passed in as form variables. I can't figure out what's wrong.
Here is LoginCtrl code as well as the login-form.html template :
(function () {
'use strict';
angular.module('routerApp').controller('LoginCtrl',
['$rootScope', '$scope', authenticate]);
function authenticate($rootScope, $scope, userService) {
var login = this;
login.loginUser = function () {
login.dataLoading = true;
//loginService.authUser(login.user, login.password); // TO DO !!!
};
login.test = function () {
var test = true;
};
}
})();
<div ng-show="error" class="alert alert-danger">{{error}}</div>
<form ng-submit="login.loginUser()" name="form">
<div class="form-group">
<label for="username">Username</label>
<i class="fa fa-key"></i>
<input type="text" name="username" id="username" class="form-control" ng-model="login.username" required />
<span ng-show="form.username.$dirty && form.username.$error.required" class="help-block">Username is required</span>
</div>
<div class="form-group">
<label for="password">Password</label>
<i class="fa fa-lock"></i>
<input type="password" name="password" id="password" class="form-control" ng-model="login.password" required />
<span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span>
</div>
<div class="form-actions">
<button type="submit" ng-disabled="form.$invalid || dataLoading" class="btn btn-danger">Login</button>
<img ng-if="login.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="/>
</div>
</form>
In my local app, it is posting the old-style form variables via the URL, and I cannot get it to fire the login.loginUser function below inside LoginCtrl.
thnk you in advance...
Bob
for some odd reason (perhaps ui-router versioning) the controllerAs is not working.
Diana´s answer is valid, but it doesn´t use the controlleras syntax.
If you still want to use it, change the ui-router setting to:
.state('login', {
url: "/login",
templateUrl: "login-form.html",
controller: 'LoginCtrl as login',
})
That should do the trick ;)
Check it out:
http://plnkr.co/edit/OCqNexVeFFxt4kUuEVc1?p=preview
The controller change I applied is:
angular.module('routerApp').controller('LoginCtrl', function ($rootScope, $scope) {
$scope.loginUser = function () {
$scope.dataLoading = true;
//loginService.authUser(login.user, login.password); // TO DO !!!
};
$scope.test = function () {
var test = true;
};
})
and in the template I removed login. from the ng-if and ng-submit.
Here is a working plunks.
The SignupCtrl controller is not binding to signup view. Even when i press the submit button it don't work. But when i place ng-controller=SignupCtrl in the form tag it works. Just wondering why ui-router state parameter controller was not working.
index.html
<html class="no-js" ng-app="mainApp" ng-controller="MainCtrl">
<head> ....
</head>
<body class="home-page">
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
...
signup.html
<div class="form-container col-md-5 col-sm-12 col-xs-12">
<form class="signup-form">
<div class="form-group email">
<label class="sr-only" for="signup-email">Your email</label>
<input id="signup-email" type="email" ng-model="user.email" class="form-control login-email" placeholder="Your email">
</div>
<!--//form-group-->
<div class="form-group password">
<label class="sr-only" for="signup-password">Your password</label>
<input id="signup-password" type="password" ng-model="user.password" class="form-control login-password" placeholder="Password">
</div>
<!--//form-group-->
<button type="submit" ng-click="createUser()" class="btn btn-block btn-cta-primary">Sign up</button>
<p class="note">By signing up, you agree to our terms of services and privacy policy.</p>
<p class="lead">Already have an account? <a class="login-link" id="login-link" ui-sref="login">Log in</a>
</p>
</form>
</div><!--//form-container-->
app.js
angular
.module('mainApp', [
'services.config',
'mainApp.signup'
])
.config(['$urlRouterProvider', function($urlRouterProvider){
$urlRouterProvider.otherwise('/');
}])
signup.js
'use strict';
/**
* #ngdoc function
* #name mainApp.signup
* #description
* # SignupCtrl
*/
angular
.module('mainApp.signup', [
'ui.router',
'angular-storage'
])
.config(['$stateProvider', function($stateProvider){
$stateProvider.state('signup',{
url: '/signup',
controller: 'SignupCtrl',
views: {
'header': {
templateUrl: '/pages/templates/nav.html'
},
'content' : {
templateUrl: '/pages/signup/signup.html'
},
'footer' : {
templateUrl: '/pages/templates/footer.html'
}
}
});
}])
.controller( 'SignupCtrl', function SignupController( $scope, $http, store, $state) {
$scope.user = {};
$scope.createUser = function() {
$http({
url: 'http://localhost:3001/users',
method: 'POST',
data: $scope.user
}).then(function(response) {
store.set('jwt', response.data.id_token);
$state.go('home');
}, function(error) {
alert(error.data);
});
}
});
There is a working plunker. Firstly, check this Q & A:
Are there different ways of declaring the controller associated with an Angular UI Router state
Where we can see, that
controller does not belong to state. It belongs to view!
This should be the state definition:
$stateProvider.state('signup',{
url: '/signup',
//controller: 'SignupCtrl',
views: {
'header': {
templateUrl: 'pages/templates/nav.html'
},
'content' : {
templateUrl: 'pages/signup/signup.html',
controller: 'SignupCtrl',
},
'footer' : {
templateUrl: 'pages/templates/footer.html'
}
}
});
Check it here
You need a template to bind a controller.
In the docs ui-router Controllers
Controllers
You can assign a controller to your template. Warning: The controller
will not be instantiated if template is not defined.
I am wondering how to include parameters when changing state and sending the request to get the template from the backend.
Here is my app:
angular.module('questionnaireApp', ['ngAnimate', 'ui.router', 'ui.bootstrap'])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('questionnaire', {
url: '/questionnaire',
templateUrl: 'questionnaire/questionnaire.html',
controller: 'questionnaireCtrl'
})
.state('questionnaire.receiver_name', {
url: '/receiver_name',
templateUrl: 'questionnaire/receiver_name.html'
})
.state('questionnaire.location', {
url: '/location',
templateUrl: 'questionnaire/location.html'
})
.state('poem', {
url: '/poem',
templateUrl: 'questionnaire/poem.html',
controller: 'questionnaireCtrl'
});
$urlRouterProvider.otherwise('/questionnaire/receiver_name');
}])
.controller('questionnaireCtrl', ['$scope', '$http', '$state', function($scope, $http, $state) {
$scope.formData = {};
}]);
I am saving user input in $scope.formData. I need to include it in my request to be able to render questionnaire/poem.html.
Something like:
.state('poem', {
url: '/poem',
templateUrl: 'questionnaire/poem' + $scope.formData + '.html',
controller: 'questionnaireCtrl'
});
How can I do that?
Or is there any variant that can help me send the formData to my backend so that it can render the poem.html page properly?
You can do it by making the templateUrl a function. Take a look at this example, taken from ui-router documentation ( https://github.com/angular-ui/ui-router/wiki ):
$stateProvider.state('contacts', {
templateUrl: function ($stateParams){
return '/partials/contacts.' + $stateParams.filterBy + '.html';
}
})
In the above example, we get $stateParams as an argument (note, it's not an injection, more details on the doc site) and use the parameter "filterBy" as part of the template url. In your case, it's formData.
Note 1: You must pass a string. If formData is an object, you can't use it as part of the templateUrl, and you probably won't be able to even pass it as part of the stateParams. maybe you want a specific field from it? Something like 'formType'?
Note 2: As mb21 mentioned, all of this has nothing to do with the backend. if you want to send the form data, do a REST call. Routing should involve only the client side.
questionnaire/poem.html should be an Angular html template file, nothing dynamically generated by the server.
To save your data, use Angular's http service to do a post request to the server that wants the data.
If you have the data on PageA with ControllerA and need to have it on PageQ with ControllerQ, you should share the data using a factory between the two controllers. No need to involve the server.
I finally managed to achieve my goal: retrieve the poem with one HTTP request only.
To do that:
I store the HTML templates inside the Angular app so that it only needs to retrieve JSON data
form data is sent with regular http post
poem data is sent back in JSON format
the poem is displayed thanks to Angular data binding
Angular code:
angular.module('thePoetApp').config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/questionnaire)
.state('questionnaire', {
url: '/questionnaire',
templateUrl: 'questionnaire/questionnaire.html',
})
// nested states
// each of these sections will have their own view
// url will be nested (/questionnaire/receiver_name)
.state('questionnaire.receiver_name', {
url: '/receiver_name',
template: '<div class="col-md-3 text-left ng-scope"></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group"><label for="receiver_name">Receiver Name:</label><input name="receiver_name" ng-model="formData.receiver_name" receiver_name="receiver_name" required="" type="text" class="ng-pristine ng-invalid ng-invalid-required"></div><div class="form-group"><label for="receiver_sex">Receiver Sex:</label><input name="receiver_sex" ng-model="formData.receiver_sex" receiver_sex="receiver_sex" required="" type="radio" value="male" class="ng-pristine ng-invalid ng-invalid-required">Male<input name="receiver_sex" ng-model="formData.receiver_sex" receiver_sex="receiver_sex" required="" type="radio" value="female" class="ng-pristine ng-invalid ng-invalid-required">Female</div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.location">Next Step</a></div>',
})
// url will be /questionnaire/location
.state('questionnaire.location', {
url: '/location',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.receiver_name">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group"><label for="location">Location:</label><input location="location" name="location" ng-model="formData.location" required="" type="text" class="ng-pristine ng-invalid ng-invalid-required"></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.relationship">Next Step</a></div>'
})
// url will be /questionnaire/relationship
.state('questionnaire.relationship', {
url: '/relationship',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.location">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="RelationshipsTypeaheadCtrl"><label for="relationship">Relationship:</label><input autocomplete="off" name="relationship" ng-model="formData.relationship" relationship="relationship" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in relationships($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.trait">Next Step</a></div>'
})
// url will be /questionnaire/trait
.state('questionnaire.trait', {
url: '/trait',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.relationship">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="TraitsTypeaheadCtrl"><label for="trait">Trait:</label><input autocomplete="off" name="trait" ng-model="formData.trait" trait="trait" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in traits($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.message">Next Step</a></div>'
})
// url will be /questionnaire/message
.state('questionnaire.message', {
url: '/message',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.trait">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="MessagesTypeaheadCtrl"><label for="message">Message:</label><input autocomplete="off" name="message" ng-model="formData.message" message="message" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in messages($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div>'
})
.state('poem', {
url: '/poem',
template: '<div class="poem"><p>{{ poem.title }}</p><p><div>{{ poem.intro_verse.line_one}}</div><div>{{ poem.intro_verse.line_two}}</div><div>{{ poem.intro_verse.line_three}}</div><div>{{ poem.intro_verse.line_four}}</div><div>{{ poem.intro_verse.line_five}}</div></p><p><div>{{ poem.trait_verse.line_one}}</div><div>{{ poem.trait_verse.line_two}}</div><div>{{ poem.trait_verse.line_three}}</div><div>{{ poem.trait_verse.line_four}}</div><div>{{ poem.trait_verse.line_five}}</div></p><p><div>{{ poem.message_verse.line_one}}</div><div>{{ poem.message_verse.line_two}}</div><div>{{ poem.message_verse.line_three}}</div><div>{{ poem.message_verse.line_four}}</div><div>{{ poem.message_verse.line_five}}</div></p><div class="text-center"><a class="btn btn-warning" ui-sref="questionnaire.receiver_name">Restart</a></div></div>'
});
// catch all route
// send users to the receiver_name page
$urlRouterProvider.otherwise('/questionnaire/receiver_name');
Angular controller:
postParams =
{"questionnaire":
{
"receiver_name": $scope.formData.receiver_name,
"receiver_sex": $scope.formData.receiver_sex,
"location": $scope.formData.location,
"relationship": $scope.formData.relationship,
"trait_category": $scope.formData.trait,
"message_category": $scope.formData.message
}
}
// send post request
$http({
method : 'POST',
url : 'api/questionnaire/poem',
data : $.param(postParams), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
})
.success(function(data) {
if (data.success) {
$scope.poem = data.poem;
$scope.formData = {};
$state.go('poem');
}
});
$scope.poem = data.poem' sets the poem data so that {{ poem.title }} and so on get replaced when going to the poem state.