I have $scope.loaded=false; in controller. Seems like directive doesn't pick up the scope, because ng-show="loaded" still shows DIV. But when I click button and controller changes $scope.sent to true, directive gets scope(it changes class as seen in directive).
Why is directive not picking $scope.loaded?
Message directive is loaded in other view:
<form class="form-horizontal" ng-submit="submit()">
<fieldset>
<!-- Form Name -->
<legend>Contact us</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Your name</label>
<div class="col-md-4">
<input id="name" name="textinput" type="text" placeholder="name" class="form-control input-md" ng-model="model.name" required>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Your email</label>
<div class="col-md-4">
<input id="from" name="textinput" type="email" placeholder="email" class="form-control input-md" ng-model="model.from" required>
</div>
</div>
<!-- Textarea -->
<div class="form-group">
<label class="col-md-4 control-label" for="textarea">Content</label>
<div class="col-md-4">
<textarea class="form-control" id="content" name="textarea" ng-model="model.content" required>your message to us</textarea>
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="singlebutton"></label>
<div class="col-md-4">
<button id="singlebutton" name="singlebutton" class="btn btn-primary" ng-click>Submit</button>
</div>
</div>
<message-directive></message-directive>
</fieldset>
</form>
I have a custom directive:
(function (angular) {
angular.module('app')
.directive('messageDirective', [function () {
return {
restrict: 'E',
templateUrl: 'partials/message-directive',
scope: true,
link: function (scope) {
scope.loaded = true;
}
};
}]);
})(angular);
TemplateUrl:
<div class="form-group">
<label class="col-md-4 control-label" for="message"></label>
<div class="col-md-4">
<div ng-show="loaded" ng-class="sent ? 'alert alert-success' : 'alert alert-danger'">
{{message}}
</div>
</div>
</div>
Controller:
(function (angular) {
angular.module('app')
.controller('contactController', [
'$scope', 'contactService', function ($scope, contactService) {
$scope.model = {};
$scope.loaded = false;
var successCallback = function () {
$scope.message = "Sent!";
$scope.sent = true;
}
var errorCallback = function () {
$scope.message = "Error!";
$scope.sent = false;
}
$scope.submit = function() {
contactService.createContact($scope.model).then(successCallback, errorCallback);
}
}]);
})(angular);
the directive load after the controller .so your code
link: function (scope) {
scope.loaded = true;
}
rewrite the $scope.loaded
return {
restrict: 'E',
templateUrl: 'partials/message-directive',
scope: false,
link: function (scope) {
scope.loaded = true;
}
};
Related
I have a form inside a bookingEdit component and a bookingInfo component containing the form's input fields. The fields inside bookingInfo component aren't being populated with the booking data. How can I get these fields to be populated using my booking-info and booking-edit components?
booking-edit.template.html
<form name="$ctrl.form" ng-submit="$ctrl.updateBooking()">
<fieldset>
<legend>Edit Booking</legend>
<booking-info booking="$ctrl.booking"></booking-info>
<button class="btn btn-success" type="submit">Save</button>
</fieldset>
</form>
booking-edit.component.js
'use strict';
angular.
module('bookingEdit').
component('bookingEdit', {
templateUrl: 'booking-edit.template.html',
controller: ['BookingService','$location',
function (BookingService,$location) {
let self = this;
self.$routerOnActivate = function(next, previous) {
self.booking = BookingService.get({ id: next.params.id });
};
self.updateBooking = function () {
BookingService.update({ id: self.booking.bookingId }, self.booking)
.$promise
.then(
function () {
$location.path('/list');
},
function (error) {
}
);
};
}
]
});
booking-info.component.js
angular.module('app').
component('bookingInfo', {
templateUrl: 'booking-details.html',
bindings: {
booking:'<'
},
controller: function(){
let self = this;
}
});
booking-details.html
<div class="form-group">
<label for="contactName">Contact Name</label>
<input required type="text" class="form-control" ng-model="booking.contactName">
</div>
<div class="form-group">
<label for="contactNumber">Contact Number</label>
<input required type="tel" class="form-control" ng-model="booking.contactNumber">
</div>
You seem to forgot the $ctrl in booking-details.html
<div class="form-group">
<label for="contactName">Contact Name</label>
<input required type="text" class="form-control" ng-model="$ctrl.booking.contactName">
</div>
<div class="form-group">
<label for="contactNumber">Contact Number</label>
<input required type="tel" class="form-control" ng-model="$ctrl.booking.contactNumber">
</div>
Hello I am little confused about how can I bind the same directive with different data from the same object
(function () {
'use strict';
angular.module('app', [])
.controller('appController', appController)
.directive('userForm', userForm);
/**#Injectable*/
function appController($http) {
let vm = this;
vm.user = {
userName: 'Test User',
email: 'test#gmail.com',
number: '1456',
address: 'zyz',
state: 'abcd',
city: 'xyz'
};
}
function userForm() {
return {
restrict: 'E',
scope: {
data:'='
},
templateUrl: 'public/app/form.directive.html',
controller: 'appController',
link: function (scope, attr, element) {
}
}
}
})();
<legend>{{headerLabel}}</legend>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label1.label1}}</label>
<div class="col-sm-9">
<input type="text" ng-model="data.userName" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label2}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="email">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label3}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="number">
</div>
</div>
<!--Main Index -->
<user-form data="vm.user"></user-form>
<user-form data="vm.user"></user-form>
Here I have used same directive two times and I want to bind the first directive with personal info like username, email and second directive should bind with address info.Is it possible to do this?
I wonder why you would want to do that, using a directive for two different purposes. I suggest creating 2 different directives for it. If you still want it, you can have a logic inside link in the directive function to perform different logics. Its not very elegant, but what you asked for is not either(imho)
(function () {
'use strict';
angular.module('app', [])
.controller('appController', appController)
.directive('userForm', userForm);
/**#Injectable*/
function appController($http) {
let vm = this;
vm.user = {
userName: 'Test User',
email: 'test#gmail.com',
number: '1456',
address: 'zyz',
state: 'abcd',
city: 'xyz'
};
}
function userForm() {
return {
restrict: 'E',
scope: {
data:'=',
type:'#'
},
templateUrl: 'public/app/form.directive.html',
controller: 'appController',
link: function (scope, attr, element) {
switch(scope.type){
case 'name_info':
//logic for name based info
break;
case 'address_info':
//logic for address based info
break;
default:
}
}
}
}
})();
<legend>{{headerLabel}}</legend>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label1.label1}}</label>
<div class="col-sm-9">
<input type="text" ng-model="data.userName" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label2}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="email">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label3}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="number">
</div>
</div>
<user-form data="vm.user" type="name_info"></user-form>
<user-form data="vm.user" type="address_info"></user-form>
I'm newbie in angularJS. I have finished phone-cat tutorial on the official angular document. I am trying to create some new feature for it such as ( create a new item , edit ... ) Assume that I created api for this.
app/phone-create/phone-create.module.js
angular.module('phoneCreate', ['core.phone'])
app/phone-create/phone-create.component.js
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
var data = {
name: $scope.name,
description: $scope.description,
kind: $scope.kind
}
self.create = function () {
console.log(data); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
app/phone-create/phone-create.template.html
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>
When I click Create , I want to fields in input will be accessed by scope in controller but it is underfined. I don't know why and how to fix. Please help me!.
Let's take a look at these three lines:
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
They have ng-models: $ctrl.name, $ctrl.description, $ctrl.kind. Your component doesn't declare those variables.
Change them to $ctrl.data.name, $ctrl.data.description, $ctrl.data.kind and modify your component:
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.data = {
name: "",
description: "",
kind: ""
};
self.create = function () {
console.log(self.data);
};
}
]
});
OPTION 1 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.create = function () {
console.log(self.name); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
OPTION 2 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
// No need to initialise self.data
self.data = {
name: '',
description: '',
kind: ''
}
self.create = function () {
console.log(self.data);
console.log(self.data.name);
}
}
]
});
HTML :
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>
I am using custom angular directive for showing validation. Directive code is as below
angularFormsApp.directive('showErrors',['$timeout', function ($timeout) {
return {
restrict: 'A',
require: '^form',
link: function (scope, el, attrs, formCtrl) {
// find the text box element, which has the 'name' attribute
var inputEl = el[0].querySelector("[name]");
// convert the native text box element to an angular element
var inputNgEl = angular.element(inputEl);
// get the name on the text box so we know the property to check
// on the form controller
var inputName = inputNgEl.attr('name');
var helpText = angular.element(el[0].querySelector(".help-block"));
// only apply the has-error class after the user leaves the text box
inputNgEl.bind('blur', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
helpText.toggleClass('hide', formCtrl[inputName].$valid);
});
scope.$on('show-errors-event', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
});
scope.$on('hide-errors-event', function () {
$timeout(function () {
el.removeClass('has-error');
}, 0, false);
});
}
}
}]);
and Html is as below
<div class="container" id="login-form">
<img src="assets/img/logo-big.png">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Login Form</h2>
</div>
<div class="panel-body">
<form name="loginForm" class="form-horizontal" novalidate>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-user"></i>
</span>
<input type="text" class="form-control" placeholder="Username" autocomplete="Off" ng-required="true" name="username" autofocus ng-model="loginUser.username">
</div>
<span class="help-block" ng-if="loginForm.username.$error.required">Username is required</span>
</div>
</div>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12" >
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-key"></i>
</span>
<input type="password" class="form-control" placeholder="Password"
name="password"
ng-model="loginUser.password" autocomplete="Off"
ng-required="true">
</div>
<span class="help-block" ng-if="loginForm.password.$error.required">Password is required</span>
</div>
</div>
<div class="form-group mb-n">
<div class="col-xs-12">
Forgot password?
<div class="checkbox-inline icheck pull-right p-n">
<label for="">
<input type="checkbox"></input>
Remember me
</label>
</div>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<div class="clearfix">
Register
Login
</div>
</div>
</div>
</div>
</div>
</div>
Controller code :
var loginController = function ($scope, $window, $routeParams, $uibModal, $location, $filter, $rootScope, DataService, SharedProperties) {
$rootScope.bodylayout = 'focused-form animated-content';
$scope.loginUser = {
username: "",
password:""
}
$scope.load = function () {
//getAppointmentInfo();
};
$scope.SubmitLoginForm = function () {
$scope.$broadcast('show-errors-event');
if ($scope.loginForm.$invalid)
return;
}
}
angularFormsApp.controller("loginController", ["$scope", "$window", "$routeParams", "$uibModal", "$location", "$filter", "$rootScope", "DataService", "SharedProperties", loginController]);
Now When I open form below input control validation span is displaying by default . When I click on Login button then its showing in red and working fine.
problem is it shouldn't show by default when Page is opend.. Please see image below
Instead of this
loginForm.password.$error.required
try this
(loginForm.$submitted || loginForm.username.$dirty) && loginForm.password.$error.required
Take a look at the ng-messages directive. Its fairly elegant. Example:
<form name="myForm">
<input type="text" ng-model="field" name="myField" required minlength="5" />
<div ng-messages="myForm.myField.$error">
<div ng-message="required">You did not enter a field</div>
<div ng-message="minlength">The value entered is too short</div>
</div>
</form>
You can then combine it with any form validation. Just place the error messages from the validators onto the elements $error object and they are automatically rendered in your UI.
I ended up here as part of my search for an issue. In my case I was using a directive with a changing minimum value like this:
ngOnChanges(changes: SimpleChanges) {
if (changes.minDate && this.control) {
this.control.updateValueAndValidity({ onlySelf: true });
}
}
This means that the form will not be updated, I removed onlySelf and it worked correctly.
this.control.updateValueAndValidity();
Just leaving this as a breadcrumb in case someone else does something similar.
I have a very simple form template and controller. But i'm unable to call a function from within the onSubmit scope function. Controller is:
angular
.module('myApp')
.controller('registerUserCtrl', registerUserCtrl);
function registerUserCtrl($scope, $location, $window, authenticationService, $http, vcRecaptchaService){
$scope.pageHeader = {
title: 'Register',
};
$scope.register = function (data) {
console.log('in scope.register ');
userService.register(data)
.success(function(data) {
console.log('setting to true.....');
authenticationService.isLoggedIn = true;
authenticationService.user = data.user;
authenticationService.token = data.token;
$location.path("/");
}).error(function(status, data) {
console.log(status);
console.log(data);
$scope.formError = "This email has already been taken";
});
}
$scope.onSubmit = function () {
console.log('in onSubmit');
//N.B. Need to veriify this
var response = vcRecaptchaService.getResponse();
$scope.formError = "";
if(!$scope.formData || !$scope.formData.email || !$scope.formData.password) {
$scope.formError = "All fields required, please try again";
return false;
} else {
console.log('$scope is ');
console.log($scope);
$scope.register($scope.formData);
}
};
}
And template is:
<div id="register-wrapper">
<form class="form-horizontal" role="form" ng-submit="onSubmit()">
<div role="alert" ng-show="formError" class="alert alert-danger">{{ formError }}</div>
<div class="form-group">
<label for="inputEmail" class="col-sm-4 control-label">Email</label>
<div class="col-sm-4">
<input type="email" class="form-control" id="inputEmail" placeholder="Email" ng-model="formData.email">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-4 control-label">Password</label>
<div class="col-sm-4">
<input type="password" class="form-control" id="inputPassword" placeholder="Password" ng-model="formData.password">
</div>
</div>
<div vc-recaptcha key="'6Lf6aQsTAAAAAACdCxN2FqHHKpz0RyF9jMJsn6h4'"></div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-10">
<button type="submit" class="btn btn-default">Register</button>
</div>
</div>
</form>
</div>
I always end up with:
undefined is not a function
at the $scope.register($scope.formData); line. I've done this many times before, but somehow now its not working...
You need to inject userSevice in your controller as dependency
angular
.module('myApp')
.controller('registerUserCtrl', registerUserCtrl);
function registerUserCtrl($scope, $location, $window, authenticationService,
$http, vcRecaptchaService, userSevice)
{