I am not very familiar with the directives in the AngularJS as I'm used on relying on controllers. Is it possible to set validity on other inputs via directive? Here is the case, I have a button and when it is clicked.. It should set a validity on a certain input text. But I just can not seem to get the code that will set the validity.
Here is the HTML code:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div class="container">
<div id="login-container">
<div class="form-group">
<span class="glyphicon glyphicon-user"></span>
</div>
<form name="loginForm" novalidate>
<div class="form-group">
dasdas -- {{ loginForm.student_code.$error.codeValidity }}
<input type="text" class="form-control text-center" name="student_code" ng-model="studentCode" placeholder="Enter Exam Code" required />
<span class="errors" id="error-student-code" ng-if="loginForm.student_code.$error.codeValidity">{{ errors }}</span>
</div>
</form>
<login-button form="loginForm"></login-button>
<button class="btn btn-primary">Register</button>
</div>
</div>
</body>
</html>
Here is the JS Code:
var app = angular.module("myApp", []);
app.directive('loginButton', loginButton);
loginButton.$inject = ["$http", "$window"];
function loginButton($http, $window){
return {
template: '<button type="button" class="btn btn-primary">Take Exam</button>',
link: function(scope, element, attrs, ctrl){
element.on('click', function(){
form = attrs.form;
form.student_code.$setValidity('codeValidity', true);
scope.errors = "Code is Invalid";
});
}
}
}
Here is a sample on plunker: http://plnkr.co/edit/kcdDgZpStQixTpGWqxOp?p=preview
PS.
I know this can be easily achieved using controllers but I would like to achieve this using directives as my practice to get used to it.
Yes, it is possible and you almost got it right. What you wanna do is pass form to isolated scope and then use in directive controller.
There is no need to add event manually, as you can use ng-click.
Otherwise you would need to use $scope.$apply.
In directives you can use linking function, but you don't have to.
In general it is good practice to keep light logic in controller and DOM manipulation in linking function.
var app = angular.module("myApp", []);
app.directive('loginButton', loginButton);
loginButton.$inject = ["$http", "$window"];
function loginButton($http, $window){
return {
template: '<button type="button" class="btn btn-primary" ng-click="click()">Take Exam</button>',
scope: {
form: '='
},
controller: function($scope){
$scope.click = function(){
form = $scope.form;
form.student_code.$setValidity('codeValidity', false);
};
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<div ng-app="myApp">
<div class="container">
<div id="login-container">
<div class="form-group">
<span class="glyphicon glyphicon-user"></span>
</div>
<form name="loginForm" novalidate>
<div class="form-group">
dasdas -- {{ loginForm.student_code.$error }}<br>
<input type="text" class="form-control text-center" name="student_code" ng-model="studentCode" placeholder="Enter Exam Code" required />
<span class="errors" id="error-student-code" ng-if="errors">{{ errors }}</span>
</div>
</form>
<login-button form="loginForm"></login-button>
<button class="btn btn-primary">Register</button>
</div>
</div>
</div>
Related
This seems like a really simple question but, for whatever reason my submit() method is not being invoked in JS.
HTML:
<ion-view title="Register" hide-nav-bar="true" nav-transition="none" id="page9">
<ion-content padding="true" class="manual-ios-statusbar-padding" scroll="false">
<form id="register-form4" ng-submit="register()" class="list">
<ion-list id="register-list4">
<label class="item item-input" id="register-input7">
<input type="text" ng-model="registration.email" placeholder="Email" required>
</label>
<label class="item item-input" id="register-input9">
<input type="password" ng-model="registration.password" placeholder="Password" required>
</label>
</ion-list>
</form>
<a id="register-button7" ng-click="document.getElementById('register-form4').submit();" class="button button-positive button-block">Create Account</a>
<a ui-sref="login" id="register-button8" class="button button-positive button-block button-clear">Back</a>
<div ng-show="isError">{{ loginError }}</div>
</ion-content>
</ion-view>
Controller:
.controller('registerCtrl', ['$scope', '$stateParams', "$firebaseAuth", "$location",
function ($scope, $stateParams, $firebaseAuth, $location) {
$scope.register = function() {
var email = $scope.registration.email,
password = $scope.registration.password,
confirmPassword = $scope.registration.confirmPassword;
console.log("Being submitted");
}
}])
I cannot change the <a> tag even though it would be easier just to have a form submit input but the HTML is auto-generated by Ionic Creator and I can't mess it up.
EDIT: The reason I want to submit the form in this way and not just trigger register() on click of the button is that I want to trigger the HTML required's in the form so that checks the fields have been entered so I don't have to do it manually
EDIT 2: I have changed the <a> tag to a submit button. However, this is still not invoking the register() method which suggests the form is not being submitted:
<input type="submit" value="Create Account" id="register-button7" class="button button-positive button-block">
Looking at these docs, it should work as it's pretty much the same format
I have read that 1 user things that the standard HTML submit and ng-submit do not work together. Anyone know if this is true?
You can use html input of type submit or a button inside your form. Here is a working demo at JSFiddle: https://jsfiddle.net/ydbhb5dL/
Controller:
angular
.module('App', [])
.controller('ExampleController', function ($scope) {
$scope.registration = {};
$scope.register = function () {
var email = $scope.registration.email,
password = $scope.registration.password;
console.log('Email:', email);
console.log('Password:', password);
console.log('Being submitted!');
};
});
Html:
<div ng-app="App" ng-controller="ExampleController">
<ion-view title="Register" hide-nav-bar="true" nav-transition="none" id="page9">
<ion-content padding="true" class="manual-ios-statusbar-padding" scroll="false">
<form id="register-form4" ng-submit="register()" class="list">
<ion-list id="register-list4">
<label class="item item-input" id="register-input7">
<input type="text" ng-model="registration.email" placeholder="Email" required>
</label>
<label class="item item-input" id="register-input9">
<input type="password" ng-model="registration.password" placeholder="Password" required>
</label>
</ion-list>
<input type="submit" class="button-like-link" value="Create Account (button)">
</form>
</ion-content>
</ion-view>
</div>
To solve your problem change the <a> element that submits the form to
<a id="register-button7" ng-click="register()" class="button button-positive button-block">Create Account</a>
The reason ngClick wasn't working before is because it was looking at $scope for document, which is not defined. You could add the following line to your controller, but it's not necessary.
$scope.document = document;
If you insist on not changing the form structure, you can create a new directive for your submit "button" similar to the one below (untested).
angular.module('moduleName').directive('submitForm', function() {
return {
restrict: 'A',
scope: {
formId: '='
},
link: function($scope, $elem) {
$elem.on('click', function() {
document.getElementById($scope.formId).submit();
});
}
};
});
Which you would then use as follows:
<a id="register-button7" submit-form form-id="register-form4" class="button button-positive button-block">Create Account</a>
If you still don't want to change the <a> tag to use the new directive, your only other option is defining $scope.document = document.
Or, as #J Orbe mentioned, you could use onclick instead of relying on an Angular directive (i.e. ngClick and submitForm). I'm not sure this qualifies as the "Angular way" TM, though, and you may want to avoid mixing Angular and regular JavaScript attributes as it can result in confusion. Typically, if you're using Angular, you should try to solve things using Angular.
I set the values of textboxes via a ajax request in my controller like this :
$http({method: 'GET', url: url}).success(function(data) {
$scope.valzz = data;
$scope.company = $scope.valzz[0].Company;
});
Then in my html :
<label class="item item-input item-stacked-label">
<span class="input-label">Company :</span>
<input type="text" placeholder="Company" value="" ng-model="company">
</label>
<button class="button button-positive" style="margin-top:10px;" ng-click="saveChanges()">
Save Changes
</button>
This correctly puts the company name in the company textbox. But when make a change to that textbox and press the save button, the new value of the textbox isnt showing - it still gets the original. This is the button click in the controller :
$scope.saveChanges=function(){
alert($scope.company);
};
Why is $scope.company not the new value of the textbox? am i doing something wrong? (sorry if basic i am new to angular)
Try removing value=""
HTML:
<label class="item item-input item-stacked-label">
<span class="input-label">Company :</span>
<input type="text" placeholder="Company" ng-model="company">
</label>
<button class="button button-positive" style="margin-top:10px;" ng-click="saveChanges()">
Save Changes
</button>
In corresponding CONTROLLER:
$scope.saveChanges = function() {
alert($scope.company);
};
You don't have a watcher for that model.
$scope.$watch('company', function(company) {
console.log(company);
}
Or in your template, you can interpolate the value:
{{company}}
And then you can see it changing on the html page, because angular make a watcher for it behind the scene
Needed to put this.company not $scope
Please define $scope.company before $http call
app.controller('myCtrl', function($scope, $http){
$scope.company = null; // <--
$http({method: 'GET', url: url}).success(function(data) {
$scope.valzz = data;
$scope.company = $scope.valzz[0].Company;
});
}
Because, once the partials has rendered, it gets only the defined properties in $scope. After that if any property is added inside $scope it needs to call the $apply.
Hope this may help you.
I would assume that you have $scope working properly, and that you have initialized the controller in your app, as well as linked to the proper controller file. Please compare your code to what I have here, as this is working properly.
HTML:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src ="controller.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="testController">
<form>
<label class="item item-input item-stacked-label">
<span class="input-label">Company :</span>
<input type="text" placeholder="Company" ng-model="company">
</label>
<button class="button button-positive" style="margin-top:10px;" ng-click="saveChanges()">
Save Changes
</button>
</form>
</div>
</body>
</html>
Controller:
(function(){
'use strict';
var app = angular.module('myApp', []);
app.controller('testController', [ '$scope', function ($scope){
$scope.saveChanges=function(){
alert($scope.company);
};
}]);
})();
Edit: Fiddle
I need to have two instances of a controller. The first instance must set a variable and the second I have to read it. The variable to set is inside the object vm (so do not use $ scope).
The code of controller is:
app.controller("AppController", function(){
var vm = this;
vm.search = null;
});
The code of first html page is:
<div class="input-group" ng-controller="AppController as app">
<input type="text" class="form-control" ng-model="app.search" placeholder="Search...">
</div>
And the code of second html page is:
<div class="input-group" ng-controller="AppController as app">
{{app.search}}
</div>
But in the second page, the value of app.search is null.
I recommend using a service to communicate data between your controller instances. This answer explains it perfectly.
But if you are keen on not using a service to share data, you can store your search variable in the $rootScope, this will make it available in all your controller instances, and in every other controller in your app. I have to warn you, this is not proper data encapsulation.
Here is how to do it:
First HTML view:
<div class="input-group" ng-controller="AppController as app">
<input type="text" class="form-control" ng-model="$root.search" placeholder="Search...">
Second HTML view:
<div class="input-group" ng-controller="AppController as app">
{{$root.search}}
</div>
I created this factory:
.factory("search", function(){
var stringaRicerca = null;
return {
getStringa: function(){
return stringaRicerca;
}, setStringa: function(stringa){
stringaRicerca = stringa;
}
};
})
And the modified controller is:
app.controller("AppController", function("search"){
var vm = this;
vm.string = search.getString;
vm.set = search.setString;
});
The first page modified is:
<div class="input-group" ng-controller="AppController as app">
<input type="text" class="form-control" ng-model="search" placeholder="Search...">
<button class="btn btn-default" ng-click="app.set(search)" type="button">GO!</button>
</div>
And the second page modified is:
<div class="input-group" ng-controller="AppController as app">
{{app.string}}
</div>
But in the second page i see anything
on my angularjs application i show a modal window to edit an event and add/remove event dates(i use bootstrap datepicker and timepicker).
the event has some fixed dates, i dont have problem with that because i have them created first and i use them on ng-model (of the datepicker & timepicker).
the problem is when the user press the add button to add new event dates dynamically, i dont have date variable to assign to the ng-model of the datepicker .
what i do to achieve that:
inside .controller('ModalEditEventP4ctrl',.. i manipulate the modal window(edit event).here i have a an empty object that i use it to add new eventdates into the directive addNewDate.
$scope.datesObj = {}
the add new eventdate button is a directive, where i pass a dates array object from the controller. Inside the directive i create new dates objects and push them on the array, so as to assign it into the html template:
.directive('addNewDate', function($compile){
return {
restrict: 'AE',
scope: {
onClick: '&',
dyndatesObj: '='
},
link: function (scope, element, attrs) {
element.bind('click', function () {
/*1. here i create new date object and push it on the array */
scope.dyndatesObj.push({dynDateStart:new Date(),dynDateEnd:new Date(),dtStatus:'1'});
/*2. get the last item */
var items = $(".row.basicDates").length-1;
/*3. compile another directive 'newDateBlock'*/
/* and pass it into the DOM*/
/* the directive it is compiled but the datepickers are empty*/
$('.row.basicDates:eq('+items+')').append($compile("<new-date-block />")(scope));
scope.$apply();
});
}
}
})
the directive newDateBlock that has the DOM elements which i compile it through the ebove directive is this:
.directive('newDateBlock', function(){
return {
restrict: 'AE',
scope: {
onClick: '&',
myDate:'='
},
templateUrl: 'assets/modules/part4/templates/addNewDate.tpl.html',
link: function (scope, element, attrs) {
element.bind('click', function () {
console.log('inside directive');
});
}
}
});
the template file addNewDate.tpl.html(i dont show it all). everything works ok , except from the datepickers that ,although i assign them ng-model= datesObj[datesObj.length-1][dynDateStart], they are empty.
<div class="row" >
<div class="col-md-6">
<div class="row">
<div class="col-md-4" style="padding-left: 0;">
<label>Start Date</label>
<label>Start Time</label>
</div>
<div class="col-md-8" style="padding-left: 0;">
<p class="input-group">
<input type="text" class="form-control" style="width:100px"
datepicker-popup="{{format}}"
/*ng-model seems not to work*/
ng-model="datesObj[datesObj.length-1][dynDateStart]"
is-open=""
datepicker-options="dateOptions"
ng-required="true"
close-text="Close"/>
<span class="input-group-btn" style="float:left">
<button type="button" class="btn btn-default" ng-click="">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<timepicker ng-model="" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
</div>
</div>
it seems that the value inside the ng-model is not compiled , i dont know exactly what is the problem. any help would be appreciated.
to be more specific, i get the error (on the browser) that says:
TypeError: Cannot read property 'initDate' of undefined
at link (http://.../bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js:8:23435)
at http://.../bower_components/angular/angular.min.js:70:141
at $ (http://.../bower_components/angular/angular.min.js:70:197)
at B (http://..../bower_components/angular/angular.min.js:59:255)
at g (http://..../bower_components/angular/angular.min.js:51:335)
at g (http://..../bower_components/angular/angular.min.js:51:352)
at g (http:/..../bower_components/angular/angular.min.js:51:352)
at g (http://.../bower_components/angular/angular.min.js:51:352)
at g (http://..../bower_components/angular/angular.min.js:51:352)
at g (http://.../bower_components/angular/angular.min.js:51:352) <input type="text" class="form-control ng-pristine ng-untouched ng-valid ng-isolate-scope" style="width:100px" datepicker-popup="{{format}}" ng-model="datesObj[0].dynDateStart" is-open="" datepicker-options="dateOptions" ng-required="true" close-text="Close">
After many hours and too many tests i quited the directives option and i made it work with functions inside the controller where i $compile the whole html template each time i add new date ,with ng-repeat , like refresh the whole DOM, i just keep the html template because it works perfect.
what i did:
1. inside my controller i created the addNewDate() function:
$scope.addNewDate = function(){
//i push the new item inside my events.eventDates object and not in another array object as previously
$scope.eventmodal.eventDates.push({eventStartDate:new Date(),eventEndDate:new Date(),dateStatus:'1'});
$templateRequest('/assets/modules/part4/templates/addNewDate.tpl.html').then(function(html){
// Convert the html to an actual DOM node
var template = angular.element(html);
// clear completely(not append) the previous block of dates and add the new ones
$('.basicDatesBlock').html(template);
// finally $compile the template and show it.
$compile(template)($scope);
});
};
2. my addNewDate.tpl.html i use the ng-repeat to show all the eventDates (the old + the new ones) like this:
<div class="row basicDates" ng-repeat="eventdate in eventmodal.eventDates track by $index" ng-show="eventdate.dateStatus == 1">
<!-- start date -->
<div class="col-md-6">
<div class="row">
<div class="col-md-4" style="padding-left: 0;">
<label>Start Date*</label>
<label>Start Time</label>
</div>
<div class="col-md-8" style="padding-left: 0;">
<p class="input-group">
<input type="text" class="form-control" style="width:100px"
datepicker-popup="{{format}}"
ng-model="eventdate.eventStartDate"
is-open="openIndex[$index]"
datepicker-options="dateOptions"
ng-required="true"
close-text="Close"/>
<span class="input-group-btn" style="float:left">
<button type="button" class="btn btn-default" ng-click="openme($index)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<timepicker ng-model="eventdate.eventStartDate" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
</div>
</div>
</div>
<!-- end date -->
<div class="col-md-6">
<div class="row">
<div class="col-md-5" style="width:31.6%;padding-right:0;">
<label>End Date*</label>
<label>End Time</label>
</div>
<div class="col-md-7">
<p class="input-group">
<input type="text" class="form-control" style="width:100px"
datepicker-popup="{{format}}"
ng-model="eventdate.eventEndDate"
is-open="openIndex[$index]"
datepicker-options="dateOptions"
ng-required="true"
close-text="Close"/>
<span class="input-group-btn" style="float:left">
<button type="button" class="btn btn-default" ng-click="openme($index)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<!-- i show the '+' button only for the first row-->
<div style="float:right" ng-show="$index==0">
<div class="plusCircle" style="margin-top:15px">
<!--<div class="plusSymbol" add-new-date dyndates-obj = datesObj>+</div>-->
<div class="plusSymbol" ng-click="addNewBasicDate()">+</div>
</div>
</div>
<!-- i show the 'X' button only for 2nd row and greater-->
<div style="float:right" ng-show="$index>0">
<div class="plusCircle" style="margin-top:15px">
<div class="plusSymbol">x</div>
</div>
</div>
<timepicker ng-model="eventdate.eventEndDate" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
</div>
</div>
</div>
And that's it. i tried to make myself clear , i hope it helps other guys with similar problems.
I am new with AngularJs
if I want to define two model in html
how do I define it?
I haved tried it much times
please help
<body ng-app="experiment">
<div ng-controller="functionCrtl" id="staff">
<div ng-modle="data1.data">
<ng-view></ng-view>
</div>
<div ng-app="experiment_left">
<div ng-controller="accordtionCrtl">
<div ng-model="accordtion.accordtion">
<ng-view></ng-view>
</div>
</div>
experiment.config (function($routeProvider) {
$routeProvider.when("/",{
templateUrl : "function1.html",
controller: 'functionCrtl'});
I want to dynamic load two page , how can I do?
But to answer your question read this http://docs.angularjs.org/api/ng.directive:input.
Controller:
angular.module('myApp').controller('CreateUserCtrl', function ($scope) {
$scope.firstname = 'John';
$scope.surname = 'Doe';
});
HTML
<form ng-controller="CreateUserCtrl">
<input ng-model="firstname " type="text" placeholder="firstname">
<input ng-model="surname" type="text" placeholder="surname">
</form>