add new angularJs event to a button on input value change using controller in angularJs - angularjs

I m trying to add angularJs event to a button if value of input field changes. But i cannot find a solution how can i do it. I know how to detect change but do not know how to add a new event using controller.
Let me illustrate by example:
<form name="addNewCourse">
<input ng-model="courseNameEdit" ng-value="courseName" ng-pattern="regex" ng-trim="false" name="addNewCourseField" ng-minlength="5" ng-maxlength="60" required>
<div ng-messages="addNewCourse.addNewCourseField.$error" style="text-align: left !important; color:red;">
<div ng-message="required">This field is required*</div>
<div ng-message="pattern">Must be only digits or numbers</div>
<div ng-message="maxlength">Must not exceed 60 characters</div>
<div ng-message="minlength">Must not be smaller than 5 characters</div>
</div>
<button class="btn btn-primary" ng-click="saveCourseNameFunc(courseNameEdit)">Save</button>
</form>
what i want is to add ng-disabled="addNewCourse.$invalid" into the button if value change using controller. Thanks in Advance.

If I'm not wrong here, You are about to validate your form while field value changes via the controller. Try below solution and let me know if this will not work for you.
FORMOBJECT.$setSubmitted();
You can also try triggering change event of that field via controller like:
angular.element('#INPUT_ID').trigger('change');
Hope you will get the solution from one of the given above.

How about using ng-change and a boolean in your ng-disabled expression activate the disability simply.
<form name="addNewCourse">
<input ng-change="changed()" ng-disabled="addNewCourse.$invalid && activeDisable" ng-model="courseNameEdit" ng-value="courseName" ng-pattern="regex" ng-trim="false" name="addNewCourseField" ng-minlength="5" ng-maxlength="60" required>
<div ng-messages="addNewCourse.addNewCourseField.$error" style="text-align: left !important; color:red;">
<div ng-message="required">This field is required*</div>
<div ng-message="pattern">Must be only digits or numbers</div>
<div ng-message="maxlength">Must not exceed 60 characters</div>
<div ng-message="minlength">Must not be smaller than 5 characters</div>
</div>
<button class="btn btn-primary" ng-click="saveCourseNameFunc(courseNameEdit)">Save</button>
</form>
and your controller must contain something like this:
$scope.activeDisable = false;
$scope.change = function(){
$scope.activeDisable = true;
}

Related

Angular: Elegant way to toggle visibility of two related inputs

I have 2 related inputs in angular one is type number and the other is type text.
They both display the same value with the only difference being that the type text input displays the value of the type number input formatted for currency.
Only one of these is displayed at any given time. The behaviour I'd like is for the text input to be displayed initially and then on the click event the text input is hidden and the number input is shown. Similarly when the blur event happens on the number input the number input is hidden and the text input is shown.
The markup for this looks something like this:
<div>
<input type="number" ng-model="aValue" ng-blur="hideMeAndShowInputBelow">
<input type="text" ng-value="aValue | currency:'': '0'" ng-click="hideMeAndShowAndFocusInputAbove" readonly="readonly">
</div>
I know I could add extra properties to make this work but being relatively new to Angular this feels like the sort of thing that there is probably an elegant solution for.
Any help would be much appreciated.
You can assign a variable in ng-blur/ng-click and hide/show the inputs depending on the variable value.
<div>
<input type="number" ng-model="aValue" ng-show="showNumber" ng-blur="showNumber = false">
<input type="text" ng-value="aValue | currency:'': '0'" ng-show="!showNumber" ng-click="showNumber = true" readonly="readonly">
</div>
Check the plunker here:
https://plnkr.co/edit/yMFiXWuUF1R9BPGr2usT?p=preview
Alternatively, if this is a component you're going to use multiple times around your app, you could create a custom directive that achieves the same functionality, and thus avoid a lot of code duplication etc.
Try out something like this
<div ng-app="myApp" ng-controller="myCtrl">
<button class="btn btn-success" type="text" ng-model="firstName" ng-show="display" ng-click="display=!display"> BUTTON 1</button>
<br />
<button class="btn btn-warning" ng-click="display=!display" ng-model="lastName" ng-show="!display"> BUTTON 2
</button>
</div>
DEMO
Thanks for the suggestions. I followed the same approach but because I had some additional requirements (I wanted the value to be focussed when switching to the edit mode so the user can edit immediately without having to click the input again) I ended up writing a directive. It's here:
PLUNKER
But here is the markup.
<div class="mt-flight-input" ng-class="{'mt-dirty': value.newvalue != value.initial, 'mt-zero': value.newvalue == 0}">
<input type="number" class="mt-input" placeholder="0" ng-show="value.isAuthoring" ng-model="value.newvalue" ng-blur="checkValue('blur', value)" ng-focus="checkValue('focus', value)">
<input type="text" class="mt-input" placeholder="0" ng-show="!value.isAuthoring" ng-value="value.newvalue | currency:'': '0'| comma2dots" ng-click="showEditor($event, value)" ng-focus="showEditor($event, value)" readonly="readonly">
</div>

AngularJS - object property binds fine to one element and doesnt want to bind to another

not sure why but the property binds just fine to textarea and doesnt want to bind to a text box...
Here is HTML:
<form method="post" ng-submit="vm.executeAction('CompleteWorkOrder')">
<div class="form-group">
<label for="resolutionNote">#("Resolution Note".T())</label>
<textarea name="resolution" class="form-control" rows="4" placeholder="Provide resolution..." ng-bind="vm.woComplete.Resolution" required></textarea>
</div>
<div class="form-group">
<label for="completionDate">#("Completion Date".T())</label>
<input type="text" name="completionDate" class="form-control" ng-bind="vm.woComplete.Resolution" required>
</div>
<label>#("MRT".T()) {{vm.data.MRT}}</label>
<button type="submit" class="btn btn-success pull-right">Submit</button>
</form>
and the result
Does anyone know why this is happening? Thanks.
The ngBind attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
In your screenshot you can see that the text you entered in the text area DOES appear between the <input> and </input> tags. But, while that's fine for a textarea, that's not how an input works. An input stores it's data in the value attribute. You would want to use ng-model to get what you want.

How to catch errors or validate angular material datepicker in the controller?

In angular material datepicker, Error messages are shown using ng-Messages but how do I catch those in the controller and validate if no error is there.
<form name="myForm">
<md-datepicker name="dateField" ng-model="myDate" md-placeholder="Enter date"
required md-min-date="minDate" md-max-date="maxDate" md-open-on-focus></md-datepicker>
<div class="validation-messages" ng-messages="myForm.dateField.$error">
<div ng-message="required">This date is required!</div>
<div ng-message="mindate">Date is too early!</div>
<div ng-message="maxdate">Date is too late!</div>
<div ng-message="valid">The entered value is not a date!</div>
</div>
{{myForm.dateField.$error}}
</form>
<button ng-click="check(myForm.dateField.$error)">Click</button>
I want to validate errors on click of button in the controller
$scope.check=function(errors){
};
Angularjs creates a scope variable for form whenever it is used to check the validation of that form. Now you can directly use form.$valid , formName.$invalid and many more pre-defined properties in html directly. But if you want to use it in the controller just pass it to the controller using md-button (while submitting the form).
<form name="myForm">
<md-datepicker name="dateField" ng-model="myDate" md-placeholder="Enter date" required="" md-min-date="minDate" md-max-date="maxDate" md-date-filter="onlyWeekendsPredicate"></md-datepicker>
<div class="validation-messages" ng-messages="myForm.dateField.$error">
<div ng-message="valid">The entered value is not a date!</div>
<div ng-message="required">This date is required!</div>
<div ng-message="mindate">Date is too early!</div>
<div ng-message="maxdate">Date is too late!</div>
<div ng-message="filtered">Only weekends are allowed!</div>
</div>
<md-button ng-click="check(myForm)">check/md-button>
</form>
Here is a working example. You can the whole object in console which is printed by controller as desired. http://codepen.io/next1/pen/rLebeK
You already got that right but missing the validation. The correct way is to check the property $scope.myForm.$valid, that will be true when the form is valid and false otherwise. Check the Developer Guide.
Other way is to check for the empty object (so no errors) but it checks for that input only:
in the HTML:
<button ng-click="check(myForm.myName.$error)">Click</button>
in the controller:
$scope.check = function (val){
// check if is empty
var ok = !!(Object.keys(val).length === 0 && val.constructor === Object);
}
I don't recommend this approach unless you want to do it yourself or deal with specific errors.
See this Plunker with both ways

bind not working for required input field

I've this AngularJS HTML using Bootstrap:
<div class="col-sm-6" ng-app ng-controller="MyController">
<br/><br/>
<form name="myForm">
<div class="input-group">
<input type="text" name="input" class="form-control" ng-model="input" maxlength="{{inputMaxLength}}" ng-minlength="{{inputMaxLength}}" ng-maxlength="{{inputMaxLength}}" placeholder="Type input.." aria-describedby="basic-addon2" required />
<span class="input-group-addon" id="basic-addon2" ng-bind="{{inputMaxLength-input.length}}"></span>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default btn-primary" ng-disabled="myForm.$invalid">Submit</button>
</div>
</form>
</div>
and this controller:
function MyController($scope) {
$scope.input = "";
$scope.inputMaxLength = 18;
}
The Bootstrap addon in the field, should always count the remaining characters. The Submit button should be disabled as long the form is not valid.
The button works as aspected, but the "count down" in the add on is always 18.
Why?
See this JSFiddle.
You have a typo in ng-min-length, you should have:
ng-minlength="{{inputMinLength}}"
instead of
ng-minlength="{{inputMaxLength}}"
Oh and you should lose the curly braces on ng-bind, you can use one or the other but not both
So either:
<span class="input-group-addon" id="basic-addon2" ng-bind="inputMaxLength-input.length"></span>
or
<span class="input-group-addon" id="basic-addon2">{{inputMaxLength-input.length}}</span>
(same applies for ng-minlength="{{inputMaxLength}}" ng-maxlength="{{inputMaxLength}}", no need for interpolation here, use ng-minlength="inputMaxLength" ng-maxlength="inputMaxLength" instead)
Note that while the input does not fulfill the requirements ie. larger than minLength and shorter than maxLength input will not have a value.
In this case you can get the value using myForm.input.$viewValue
I have updated you fiddle http://jsfiddle.net/29m5tdsc/9/
This can't work : your ng-validation (ng-minlength) will set $scope.input to null. So your counter wont work.
Besides, you wrote :
ng-bind="{{inputMaxLength - input.length}}"
When angular will work he will replace variables with values. You should wrote :
ng-bind="(inputMaxLength - input.length)"
JS Fiddle

Ng-model does not update view

I have searched thoroughly everywhere and can't seem to find the solution to my problem.
I am trying to make a form to fill in to create new task object onto projects on the website like a scrum backlog or something in Angular and angular-ui.
I use Angular-UI for typeahead functionality for when adding team members to a task, so available members on a project pop-up. I have seen guys with similar problems, but nothing seems to solve it for me. Below is the HTML and the controller. Sorry for the long markup, but I suspect it has to do something with nesting the controllers and mixing the scopes, so I'm including everything relevant.
<div ng-controller="SubmitCreateTaskController">
<div class="modal fade" id="taskModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title" id="myModalLabel">New Task</h4>
</div>
<div class="modal-body">
<form role="form" method="post" name="create-task">
<div class="form-group">
<label for="taskname">Task Name</label>
<input type="text" class="form-control" id="taskname" ng-model="taskForm.taskName" placeholder="Task Name">
</div>
<div class="form-group">
<label for="taskdesc">Description</label>
<textarea class="form-control" id="taskdesc" size="3" ng-model="taskForm.taskDescription" placeholder="Enter a short description here..." rows="2"></textarea>
</div>
<div class="form-group">
<label for="assigneddate">Assigned Date</label>
<input type="text" class="form-control" id="assigneddate" ng-model="taskForm.assignedDate">
</div>
<div ng-controller="TypeAheadController">
<div class="form-group">
<label for="contributors">Add Contributors</label>
<input id="contributors" type="text" class="form-control" ng-model="contrib.selected" typeahead="member for member in contrib.stream_members | filter:$viewValue"
typeahead-editable="false" typeahead-on-select="contrib.onSelect($item)">
</div>
<div class="form-group">
<label for="users">Contributors:</label>
<textarea class="form-control" disabled="disabled" id="users" ng-model="contrib.entered" rows="1"></textarea>
</div>
</div>
<div class="form-group">
<label for="taskcomments">Comments</label>
<textarea class="form-control" id="taskcomments" ng-model="taskForm.comment" placeholder="Comments" rows="2"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="taskForm.submit()">Add Task</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
</div>
</form>
</div>
</div>
</div>
</div>
Controllers:
.controller('SubmitCreateTaskController', ['$scope', '$http', function($scope, $http) {
$scope.taskForm = {};
$scope.taskForm.taskName = '';
$scope.taskForm.taskDescription = '';
$scope.taskForm.assignedDate = new Date();
$scope.taskForm.contributors = [];
$scope.taskForm.comment = '';
$scope.taskForm.submit = function(item, event) {
var formData = {name: $scope.taskForm.taskName,
description: $scope.taskForm.taskDescription,
status: 'open',
assigned: $scope.taskForm.assignedDate,
completed: null,
contributors: $scope.taskForm.contributors,
comments: [{body: $scope.taskForm.comment,
user: 'RACHE User',
date: new Date()
}]
};
var postURL = '../create_task/' + $scope.stream_name;
$http.post(postURL, formData)
.success(function(){
taskForm = {}; // empty the form of previous input values
alert('New Task Created for ' + $scope.stream_name);
})
.error(function(res) {
alert(res.data);
});
};
}])
.controller('TypeAheadController', ['$scope', '$http', function($scope, $http) {
$scope.contrib = {};
$scope.contrib.selected = '';
$scope.contrib.stream_members = undefined;
$scope.contrib.entered = [];
$http.get('/stream_members/' + $scope.stream_name)
.then(function(res) {
$scope.contrib.stream_members = res.data.stream_members;
});
$scope.contrib.onSelect = function($item) {
$scope.contrib.selected = '';
$scope.contrib.entered.push($item);
console.log($scope.contrib.entered);
};
This last bit is the important part in 'TypeAheadController'. I am trying to add the poped-up team members to a textarea just below which would be sent to the DB later. That is why I have bound the actual typeahead input box to 'contrib.select' and the "display/post" box to 'contrib.entered', so the search can be continued after adding one member, the search box is cleared, selected member is added to box below, new search can begin. In the mark up I call the last (onSelect) function in the typeahead-on-select callback. This so that I can clear the input box and another member can be easily added without deleting manually. IN this function the entered member should be appended to the array that is bound to below "display/post" box. This happens, since the console log shows good value, the search/input field gets cleared, so the function gets called as well.
The view does not get updated with the updated array bound to display box however. I have tried EVERYTHING. I have googled around and found it here that dot notation needs to be used as Angular can't update with primitives, but this hasn't helped either.
Everything works fine, the logic is good, values are good when I print them out, pop-up works and clears up as expected, but The damn textarea under it does not get updated.
Any suggestions? I have been stuck on this for almost a day now and I am really frustrated by this. I would be ever so greatfull for any help!
Thanks guys in advance!
Textarea do use the value attribute, your code isn't working because contrib. entered isn't between the tags, but because you can not bind the textarea to an array (it needs to bind to a string).
look at this plunker, if you do this in your html:
<textarea class="form-control" disabled="disabled" id="users" rows="1" ng-model="contrib.enteredString"></textarea>
and add this line at the end of your typeahead controller:
$scope.contrib.enteredString = $scope.contrib.entered.toString();
then the text area will update
Textareas don't use the ng-value as their value is contained within the tag. Remove the ng-model and put the value between the tags.
<textarea class="form-control" disabled="disabled" id="users" rows="1">{{contrib.entered}}</textarea>

Resources