Trying to send the values from HTML to controller - angularjs-directive

I am trying to send the values from html to controller but is not goes to controller. What is the problem with this code value is show undefined at controller and factory. I hope this code is easy understood:
var mymodal = angular.module('mymodal', []);
mymodal.controller('MainCtrl', function($scope, loginfactory) {
$scope.showModal = false;
$scope.toggleModal = function() {
$scope.showModal = !$scope.showModal;
};
$scope.doLogin = function() {
var promise = loginfactory.logincheck($scope.userid, $scope.pwd);
}
});
mymodal.factory("loginfactory", function($http, $q) {
return {
"logincheck": function(userid, pwd) {
console.log(userid);
console.log(pwd);
return Object;
}
};
});
mymodal.directive('modal', function() {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude=""></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace: true,
scope: true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value) {
if (value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
});
});
}
};
});
My view:
<div ng-controller="MainCtrl" class="container">
<h1>Modal example</h1>
<button ng-click="toggleModal()" class="btn btn-default">Open modal</button>
<modal title="Login form" visible="showModal">
<form role="form">
<div class="form-group">
<label for="email">Email address</label>
<input type="text" class="form-control" ng-model="userid" placeholder="Enter email" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" ng-model="pwd" placeholder="Password" />
</div>
<button type="submit" ng-click="doLogin()" class="btn btn-default">Submit</button>
</form>
</modal>
</div>

Here is what I mean see Plunker;
In your directive you used: scope: true, this mean what is change in the directive will not reflect on the parent scope Look at this so to get it works you have to do like this. in the submit btton: (angular best practice passing scope from view)
<button ng-click="doLogin(userid,pwd)" class="btn btn-default">submit</button>
in your controler:
$scope.doLogin = function(userid,pwd) {
var promise = loginfactory.logincheck(userid, pwd);
}
you see I don't pass $scope.userid and $scope.pwd in your loginfactory but pass the value from view because of scope: true, make your code won't work.
one last suggest, you can use UI bootstrap for angular so you don't have to mix with jquery bootstrap. UI Bootstrap

Related

AngularJS hiding input field

I am writing a login page with register and login options using AngularJS. There are three input fields: username, password and name. I want name field to appear when I click to register button and disappear when I click to login button. Therefore I want to change input field's class to 'hidden' on click and let css handle the job. How can I do it using AngularJS? Is there a better way to hide the name input field?
HTML:
<h2>Welcome to Mail Service</h2>
<form action="/action_page.php">
<div class="imgcontainer">
<img src="images/img_avatar2.png" alt="Avatar" class="avatar">
</div>
<div class="container">
<label><b>Username</b></label><br>
<input type="text" placeholder="Enter Username" name="uname" required ng-model="user.username"><br>
<label><b>Password</b></label><br>
<input type="password" placeholder="Enter Password" name="psw" required ng-model="user.password"><br>
<!-- NAME INPUT FIELD -->
<div class="textField-hidden">
<label><b>Name</b></label><br>
<input type="text" placeholder="Enter Name" ng-model="user.name">
</div><br>
<button type="submit" ng-click="login()">Login</button><br>
<button type="submit" ng-click="register()">Register</button>
</div>
</form>
AngularJS Controller:
app.controller('LoginCtrl', ['$scope', '$resource', '$location',
function($scope, $resource, $location)
{
$scope.login = function()
{
var loginRequest = $resource('/api/login');
loginRequest.save($scope.user, function(response)
{
});
};
$scope.register = function()
{
var registerRequest = $resource('/api/register');
loginRequest.save($scope.user, function(response)
{
});
};
}]);
You need to use ng-hide or ng-show directive (based on your context), and provide it with appropriate condition value like this:
$scope.showName = false;
$scope.login = function() {
// Your code
$scope.showName = false;
}
$scope.register = function() {
// Your code
$scope.showName = false;
}
Change your HTML accordingly:
<input ng-show="showName" type="{{type}}" placeholder="Enter Name" ng-model="user.name">
In this way, the input box will be shown only if the expression of ng-show evaluates to true. Alternatively, ng-if can be used similar to ng-show, but it works a bit different.
just populate a variable as true when you click register and set that variable as false when you click login.
<h2>Welcome to Mail Service</h2>
<form action="/action_page.php">
<div class="imgcontainer">
<img src="images/img_avatar2.png" alt="Avatar" class="avatar">
</div>
<div class="container">
<label><b>Username</b></label><br>
<input type="text" placeholder="Enter Username" name="uname" required ng-model="user.username"><br>
<label><b>Password</b></label><br>
<input type="password" placeholder="Enter Password" name="psw" required ng-model="user.password"><br>
<!-- NAME INPUT FIELD -->
<div class="textField-hidden" ng-show="register">
<label><b>Name</b></label><br>
<input type="text" placeholder="Enter Name" ng-model="user.name">
</div><br>
<button type="submit" ng-click="login()">Login</button><br>
<button type="submit" ng-click="register()">Register</button>
now populate $scope.register as true when you click register
app.controller('LoginCtrl', ['$scope', '$resource', '$location',
function($scope, $resource, $location)
{
$scope.register=false;
$scope.login = function()
{
var loginRequest = $resource('/api/login');
$scope.register=false;
loginRequest.save($scope.user, function(response)
{
});
};
$scope.register = function()
{
var registerRequest = $resource('/api/register');
$scope.register=true;
loginRequest.save($scope.user, function(response)
{
});
};
}]);
You can use a variable for input fields type and hide it
HTML:
<input type="{{type}}" placeholder="Enter Name" ng-model="user.name">
JS:
app.controller('LoginCtrl', ['$scope', '$resource', '$location',
function($scope, $resource, $location)
{
$scope.login = function()
{
$scope.type="hidden";
var loginRequest = $resource('/api/login');
loginRequest.save($scope.user, function(response)
{
});
};
$scope.register = function()
{
$scope.type="text";
var registerRequest = $resource('/api/register');
loginRequest.save($scope.user, function(response)
{
});
};
}]);
An alternative will be to use ng-if or ng-hide/ng-show defined on a $scope variable and trigger a boolean value for this variable according to your needs.

Getting form name into directive

I have a modal pop up.To open modal pop up i have a following code
mymodule.directive('modalDialogSite', function() {
return {
restrict: 'E',
scope: {
show: '='
},
replace: true,
transclude: true,
link: function(scope, element, attrs) {
scope.dialogStyle = {};
if (attrs.width)
scope.dialogStyle.width = attrs.width;
if (attrs.height)
scope.dialogStyle.height = attrs.height;
if (attrs.overflow)
scope.dialogStyle.overflow = attrs.overflow;
scope.hideModal = function() {
scope.show = false;
};
},
template: "<div class='ng-modal' ng-show='show'><div class='ng-modal-overlay'></div><div class='ng-modal-dialog' ng-style='dialogStyle'><div class='ng-modal-close' ng-click='hideModal()'><i class='fa fa-times-circle'></i></div><div class='ng-modal-dialog-content' ng-transclude></div></div></div>"
};
});
In view page the code like below
<a data-toggle="modal" role="button" class="btn btn-success" ng-click="add_site()" data-backdrop="static"><i class="icon-bookmark"></i><b>Add Site</b></a>
<modal-dialog-site show='modalShown_site'>
<?php echo $this->load->view('sites/modal_sites/content/add_website');?>
</modal-dialog-site>
When i click this button it goes to add_site() function in my controller i have given code like below
mymodule.controller('myCtrl',function($scope){
$scope.modalShown_site = !$scope.modalShown_site;
$scope.add_sute = function()
{
$scope.modalShown_site = ! $scope.modalShown_site;
}
});
Actually i have load my form here
<modal-dialog-site show='modalShown_site'> <?php echo $this->load->view('sites/modal_sites/content/add_website');?‌​> </modal-dialog-site>
and my form will be like
<form id='frmAddSite' name='frmAddSite' novalidate angular-validator angular-validator-submit="add_website(frmAddSite)" class="form-horizontal form-validate" method="POST">
<label for="textfield" class="control-label">Name</label>
<input name='site_name' ng-model="text.site_name" required required-message="'Site name is required'" type="text">
<input type="submit" class="btn btn-primary" value="Submit">
<button type="button" ng-click="frmAddSite.reset();add_site_cancel()" class="btn" data-dismiss="modal" aria-hidden="true">cancel</button>
</form>
In this scenario how can get the form name into directives?
In this sample, we create a directive to get the some attributes name,id of a element form
app.directive('myDirective', function () {
return {
transclude: true,
template: '<div class="something" ng-transclude></div>',
link: function(scope, element) {
var formName = element.find("form").attr("name");
var formId = element.find("form").attr("id");
console.log(formName);
console.log(formId);
}
}
});

How can I pass controller scope to a partial html file?

This is my main HTML file.
<div ng-controller="filterController">
<div class="quick-view" id="quickview" data-toggle="modal" data-target="#modal-bar"
ng-click="quickView(quickview)"><i class="fa fa-eye">
</i><span>Quick View</span></div>
</div>
This is my controller.js file
angular.module('myApp',[]).controller('filterController', function($scope) {
$scope.quickView = function quickView(id){
$.ajax({
type: 'GET',
url: 'assets/external/_modal.html',
data: id,
success: function (data) {
// Create HTML element with loaded data
$('body').append(data);
console.log('body append');
},
error:function(jqXHR,textStatus,exception){console.log('Exception:'+exception);}
});
}
$scope.venue = "India";
}
This is _modal.html
<div ng-controller="filterController">
<p>Hi. I live in {{venue}}</p>
</div>
How can I pass the controller scope to the external file _modal.html so that "I live in India" gets displayed instead of "I live in {{venue}}"?
Try angularjs way. Use uib modal. https://angular-ui.github.io/bootstrap
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope,$uibModal, $log, $document) {
$scope.animationsEnabled = true;
$scope.Venue = "India"; // declare venue
$scope.open = function (size, parentSelector) {
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
appendTo: parentElem,
resolve: {
values: function () {
return $scope.Venue; //we are passing venue as values
}
}
});
modalInstance.result.then(function () {
$scope.msg = "Submitted";
$scope.suc = true;
}, function(error) {
$scope.msg = 'Cancelled';
$scope.suc = false;
});
};
});
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope,$uibModalInstance, values) { // inject that resolved values
$scope.Venue= values; // we are getting & initialize venue from values
$scope.ok = function () {
$uibModalInstance.close('ok');
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ModalDemoCtrl" class="modal-demo">
<br>
<form name="form" novalidate>
Type your venue : <input type="text" style="width:200px" class="form-control" name="name" ng-model="Venue" required><br>
<button type="button" ng-disabled="form.$invalid" class="btn btn-default" ng-click="form.$valid && open()">See Venue</button>
</form><br>
<p ng-hide="!msg" class="alert" ng-class="{'alert-success':suc, 'alert-danger':!suc}">{{msg}}</p>
</div>
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">Your Details</h3>
</div>
<div class="modal-body" id="modal-body">
<p>The venue is <b>{{Venue }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">Submit</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
</script>
</body>
</html>

"[object object]" shown when double-clicking input

Below is the template I am using for the directive. In code we are
fetching the data from a service in that data we have all the
information of that particular person. And from that data we are
showing only first name, last name and designtion or company
affiliation.
<div ng-if="model" class="entry-added">
<span class="form-control"><b>{{model.fullName}}</b>, <br/><span class="small-font">{{(model.designation)?model.designation:model.companyAffiliation}}</span></span>
<a ng-click="removePerson()" class="action-remove"><i class="fa fa-remove"></i></a>
</div>
<div ng-show="!model" class="input-group">
<input type="text"
class="form-control"
name="{{name}}"
id="{{name}}"
placeholder="{{placeholder}}"
ng-required="{{isRequired}}"
typeahead-on-select = "change($item, $model, $label)"
ng-model="model"
typeahead-min-length="3",
typeahead="suggestion for suggestion in searchEmployees($viewValue)"
typeahead-template-url="typeAheadTemplate.html"
typeahead-loading="searching"
typeahead-editable="false">
<script type="text/ng-template" id="typeAheadTemplate.html">
<a class="ui-corner-all dropdown" tabindex="-1">
<div class="col-md-2"><img class="dropdown-image" ng-src="https://people.***.com/Photos?empno={{match.model.employeeNumber}}"></div>
<div>
<div bind-html-unsafe="match.model.fullName"></div>
<div bind-html-unsafe="match.model.designation"></div>
</div>
</a>
</script>
I am using a custom directive to display a search field. The drop down is displaying [object object].
Directive
// In backend taxDeptContact is a Person type object
/*
Directive code
*/
(function () {
'use strict';
angular.module('treasuryApp.directives').directive('employeeSearch', employeeSearch);
employeeSearch.$inject = ['$resource', '$rootScope', 'ErrorHandler'];
function employeeSearch($resource, $rootScope, ErrorHandler) {
return {
restrict: 'E',
require: '^form',
scope: {
model: "=",
isRequired: '#',
submitted: "=",
onSelect: '&',
name: '#',
index:'#'
},
link: function(scope, el, attrs, formCtrl) {
//set required attribute for dynamically changing validations
scope.searchEmployees = function (searchTerm) {
var users = [];
var myResult = [];
var result = $resource($rootScope.REST_URL + "/user/getEmployees", {term: searchTerm}).query().$promise.then(function (value) {
//console.log(value)
$.each(value, function(i, o) {
users.push(o);
});
return users;
});
return result;
}
scope.removePerson = function() {
scope.model=null;
}
scope.userNotSelectedFromTypeahead = function(name) {
if(undefined === formCtrl[name]) {
return false;
}
return formCtrl[name].$error.editable;
};
scope.change = function(item, model, label) {
scope.model = item
scope.onSelect(
{name: scope.name, person: scope.model});
},
templateUrl: 'app/components/common/directives/employee-search.tpl.html'
};
}
})();
View that is using the directive
<div class="form-group">
<label class="col-sm-3>Tax Dept Contact</label>
<div class="col-sm-4">
<employee-search model="reqCtrl.requestObj.taxDepartmentContact" name="taxDeptContact" is-required="false" submitted="reqCtrl.submitted"/>
</div>
</div>
Image of the error occuring
Looks like this may be your trouble spot
typeahead="suggestion for suggestion in searchEmployees($viewValue)"
suggestion for suggestion is pulling the whole object. Have you tried displaying a particular attribute of suggestion?
For example: if you had a suggestion.name attribute you would write:
typeahead="suggestion.name for suggestion in searchEmployees($viewValue)"
Finally got the answer: I used autocomplete="off" in my directive and thats all
<input type="text" autocomplete="off" />

angularjs: Better way to use ngModel.$asynValidators

I just want to asked if there's a better way to improve my user validation codes.
directive.js
angular.module('installApp')
.directive('usernameValidator', function ($q, $timeout, $http) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.username = function(modelValue, viewValue) {
return $http.post('../api/v1/checkUsers', {user: {'username':viewValue}}).then(
function(response){
scope.checkUsers = response.data;
var deferred = $q.defer();
$timeout(function() {
if(scope.checkUsers['status'] == 404){
deferred.reject();
}else{
deferred.resolve();
}
}, 2000);
return deferred.promise;
});
};
}
}
});
accounts.html
<form name="myForm" ng-submit="submit()">
<div>
<label>Username: <input type="text" ng-model="signup.username" name="username" required username-validator>
</label>
<div ng-if="myForm.username.$dirty">
<div ng-messages="myForm.username.$error" class="validation-error">
<div ng-message="required">Username required</div>
<div ng-message="username">Username already in use</div>
</div>
<div ng-messages="myForm.username.$pending" class="validation-pending">
<div ng-message="username">Checking username availability... </div>
</div>
</div>
</div>
<div>
<label>Password: <input type="password" ng-model="signup.password" name="password" required></label>
<div ng-messages="myForm.password.$error" ng-if="myForm.password.$dirty" class="validation-error">
<div ng-message="required">Password required</div>
</div>
</div>
<button type="submit" ng-disabled="myForm.$invalid || myForm.$pending">Submit</button>
</form>
The above code is perfectly working fine, but there is a doubt in my mind on how can I improve it in a better way. I've seen many examples and I noticed they didn't used mostly the if/ else condition. Please help
One thing you could do is try to make your directive reusable.
A good example I found on the internet is coming from Year of moo
angular
.module('yourmodule')
.directive('recordAvailabilityValidator',
['$http', function($http) {
return {
require : 'ngModel',
link : function(scope, element, attrs, ngModel) {
var apiUrl = attrs.recordAvailabilityValidator;
function setAsLoading(bool) {
ngModel.$setValidity('recordLoading', !bool);
}
function setAsAvailable(bool) {
ngModel.$setValidity('recordAvailable', bool);
}
ngModel.$parsers.push(function(value) {
if(!value || value.length == 0) return;
setAsLoading(true);
setAsAvailable(false);
$http.get(apiUrl, { v : value })
.success(function() {
setAsLoading(false);
setAsAvailable(true);
})
.error(function() {
setAsLoading(false);
setAsAvailable(false);
});
return value;
})
}
}
}]);