AngularJS, set class on button when input has change - javascript

I have an input field that is a filter for a long list. Next to the input field is a search icon. Basically when the user starts typing, I need to change the icon class.
I have my text field setup like so:
<input type="text" ng-change="change()" ng-model="query" />
<button class="btn"><i class="icon-search"></i></button>
Inside my controller I have defined:
$scope.change = function()
{
//change the class of button based on the length of the input field
}
Not really sure how I go about determining if there is input in the field using angular and changing the class. Am I taking the right approach here? Thanks

You can use ng-class on your ng-model
<i ng-class="{'icon-search': query.length}"></i>

Just use ngClass. Your function $scope.change should return the class name, so
<button ng-class="change()"><i class="icon-search"></i></button>
and your controller function would look something like:
$scope.change = function() {
if(something){
return "classA";
}
else{
return "classB";
}
};

Related

Disable input with dynamically generated fields in Angular

Imagine this:
http://jsfiddle.net/wcuuj8do/9/
My current code:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.rowData = [];
$scope.addRow = function(title, number)
{
$scope.rowData.push({
'title': title,
'number': number
});
};
$scope.addRow('Car', '1200');
$scope.addRow('Car','');
}
When i type "Car" inside first input (T1) and then type some text to input (N1) i want angular to check each T# input if has same value as (T1). If has disable (or readonly) all N# inputs related to currently checked T# input.
Afterwards when i remove duplicated values from T# fields, related T# fields should be returned to default input states (remove disable / readonly)
This should work by adding new dynamic inputs as seen in fiddle.
You should create a method, that will do the checking part. This method will should be bound to blur or change event on T# inputs, depends on what you want.
The method will check for duplicity, and if found, mark the object, e.g. add new property disabled: true. This property will be then used in the template on N# fields via ng-disabled directive.
Here is your update fiddle: http://jsfiddle.net/wcuuj8do/10/
Note the new method $scope.checkDuplicity and new binding:
<tr ng-repeat="(key, item) in rowData">
<td>T{{ ($index+1) }}: <input type="text" ng-model="rowData[key].title" ng-change="checkDuplicity(key)" value="" style='margin-bottom:15px' /></td>
<td>N{{ ($index+1) }}: <input type="text" ng-model="rowData[key].number" value="" style='margin-bottom:15px' ng-disabled="rowData[key].disabled" /></td>
</tr>

Angular UI-Bootstrap Typeahead: Accept top item as selected on ENTER

Simple question, but is there a way to have the first item in the dropdown results be the selected item when ENTER is pressed?
An example of this is the user types in "PC0" and sees "PC001" listed as the first option, can we have it use "PC001" on the typeahead-on-select option when ENTER is hit?
I am currently using typeahead-on-select to run a function that calls the input via id and grabs the Value for use in the function. It seems to use what was entered into the textbox instead of the selected value, either on ENTER or Click.
HTML:
<input id="applicationComboBox"
type="text"
ng-model="applicationComboBox"
uib-typeahead="a as a.Value for a in applicationList | filter:$viewValue"
typeahead-on-select="getApplication()"
class="form-control">
JS for the getApplicationValue() looks like this:
$scope.getApplication = function () {
$scope.ApplicationValue = applicationComboBox.value;
}
The issue is the applicationComboBox.value is what text the user has typed into the input at the time of the click/enter instead of the clicked/highlighted value respectively. So in previous example "PC0" would be the value instead of "PC001".
When the user selects/press enter the ng-model applicationCombox is is updated automatically. If you want another value $scope.ApplicationValue to be updated after the selection, do the following
$scope.applicationCombox = ""; //your existing model.
$scope.getApplication = function () {
$scope.ApplicationValue = $scope.applicationCombox;
}
Let us know.
I was able to get a solution that worked for me.
HTML:
<input id="applicationComboBox"
type="text"
ng-model="applicationComboBox"
uib-typeahead="a as a.Value for a in applicationList | filter:$viewValue"
typeahead-on-select="onApplicationSelect($item, $model, $label, a)"
class="form-control">
JS:
$scope.onApplicationSelect = function (item, model, label, application) {
applicationComboBox.value= item.Value;
}

Angular input inside of directive

I have an angular directive that I'm building with some pagination controls.
<div>
<!-- table logic here -->
</div>
<div>
<button bg-click="current=prevPage(current);">Prev</button>
<input ng-model="current" />
/{{pages}}
<button bg-click="current=nextPage(current);">Next</button>
</div>
It works fine, but of course when you change the value in the input.
It will also pick up the empty string during the delete before you enter a new value in.
Is there a way to sniff that out in the directive before it actually fires the change in the current value.
You can just check the value of the variable current before do pagination.
I assumes that you are using $watch() to listen the change of your variable current.
code inside your directive's link,
scope.$watch("current", function(newVal, oldVal){
if(angular.isNumber(newVal)){
// your variable is a number
// Do your pagination here
}
});
ngModelOptions is useful in such a case. You could write like this
<input ng-model="current" ng-model-options="{ updateOn: 'default', debounce: {'default': 500, 'blur': 0} }" />
to delay update value to model 500ms in default and update immediately if lost focus.
That question also has been answered several times, so you should be able to find further information in the other questions.
UPDATE:
$scope.$watch(
function() {
return $scope.current;
}, function(oldVal, newVal) {
if (!newVal) {
$scope.current = oldVal
}
}
);
If oldVal is also null or an empty string, you could copy $scope.current to another scope variable (say $scope.savedCurrent) whenever newVal has a value and copy it back to $scope.current if not.
I maybe understand wrong your question.
This will update the model only when you click outside the input
<input ng-model="current" ng-model-options="{updateOn: 'blur'}" />
Or another way, when you change the input value it call a function who test if the new value is valid and set it in current.
Html :
<div>
<button bg-click="current=prevPage(current);">Prev</button>
<input type="number" ng-model="currentInput" ng-change="changeCurrent()" />
/{{pages}}
<button bg-click="current=nextPage(current);">Next</button>
</div>
Controller :
$scope.currentInput = $scope.current;
$scope.changeCurrent = function(){
if ($scope.currentInput!=""){
$scope.current = $scope.currentInput;
}
}

AngularJS does not send hidden field value

For a specific use case I have to submit a single form the "old way". Means, I use a form with action="". The response is streamed, so I am not reloading the page. I am completely aware that a typical AngularJS app would not submit a form that way, but so far I have no other choice.
That said, i tried to populate some hidden fields from Angular:
<input type="hidden" name="someData" ng-model="data" /> {{data}}
Please note, the correct value in data is shown.
The form looks like a standard form:
<form id="aaa" name="aaa" action="/reports/aaa.html" method="post">
...
<input type="submit" value="Export" />
</form>
If I hit submit, no value is sent to the server. If I change the input field to type "text" it works as expected. My assumption is the hidden field is not really populated, while the text field actually is shown due two-way-binding.
Any ideas how I can submit a hidden field populated by AngularJS?
You cannot use double binding with hidden field.
The solution is to use brackets :
<input type="hidden" name="someData" value="{{data}}" /> {{data}}
EDIT : See this thread on github : https://github.com/angular/angular.js/pull/2574
EDIT:
Since Angular 1.2, you can use 'ng-value' directive to bind an expression to the value attribute of input. This directive should be used with input radio or checkbox but works well with hidden input.
Here is the solution using ng-value:
<input type="hidden" name="someData" ng-value="data" />
Here is a fiddle using ng-value with an hidden input: http://jsfiddle.net/6SD9N
You can always use a type=text and display:none; since Angular ignores hidden elements. As OP says, normally you wouldn't do this, but this seems like a special case.
<input type="text" name="someData" ng-model="data" style="display: none;"/>
In the controller:
$scope.entityId = $routeParams.entityId;
In the view:
<input type="hidden" name="entityId" ng-model="entity.entityId" ng-init="entity.entityId = entityId" />
I've found a nice solution written by Mike on sapiensworks. It is as simple as using a directive that watches for changes on your model:
.directive('ngUpdateHidden',function() {
return function(scope, el, attr) {
var model = attr['ngModel'];
scope.$watch(model, function(nv) {
el.val(nv);
});
};
})
and then bind your input:
<input type="hidden" name="item.Name" ng-model="item.Name" ng-update-hidden />
But the solution provided by tymeJV could be better as input hidden doesn't fire change event in javascript as yycorman told on this post, so when changing the value through a jQuery plugin will still work.
Edit
I've changed the directive to apply the a new value back to the model when change event is triggered, so it will work as an input text.
.directive('ngUpdateHidden', function () {
return {
restrict: 'AE', //attribute or element
scope: {},
replace: true,
require: 'ngModel',
link: function ($scope, elem, attr, ngModel) {
$scope.$watch(ngModel, function (nv) {
elem.val(nv);
});
elem.change(function () { //bind the change event to hidden input
$scope.$apply(function () {
ngModel.$setViewValue( elem.val());
});
});
}
};
})
so when you trigger $("#yourInputHidden").trigger('change') event with jQuery, it will update the binded model as well.
Found a strange behaviour about this hidden value () and we can't make it to work.
After playing around we found the best way is just defined the value in controller itself after the form scope.
.controller('AddController', [$scope, $http, $state, $stateParams, function($scope, $http, $state, $stateParams) {
$scope.routineForm = {};
$scope.routineForm.hiddenfield1 = "whatever_value_you_pass_on";
$scope.sendData = function {
// JSON http post action to API
}
}])
I achieved this via -
<p style="display:none">{{user.role="store_user"}}</p>
update #tymeJV 's answer
eg:
<div style="display: none">
<input type="text" name='price' ng-model="price" ng-init="price = <%= #product.price.to_s %>" >
</div>
I had facing the same problem,
I really need to send a key from my jsp to java script,
It spend around 4h or more of my day to solve it.
I include this tag on my JavaScript/JSP:
$scope.sucessMessage = function (){
var message = ($scope.messages.sucess).format($scope.portfolio.name,$scope.portfolio.id);
$scope.inforMessage = message;
alert(message);
}
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
<!-- Messages definition -->
<input type="hidden" name="sucess" ng-init="messages.sucess='<fmt:message key='portfolio.create.sucessMessage' />'" >
<!-- Message showed affter insert -->
<div class="alert alert-info" ng-show="(inforMessage.length > 0)">
{{inforMessage}}
</div>
<!-- properties
portfolio.create.sucessMessage=Portf\u00f3lio {0} criado com sucesso! ID={1}. -->
The result was:
Portfólio 1 criado com sucesso! ID=3.
Best Regards
Just in case someone still struggles with this, I had similar problem when trying to keep track of user session/userid on multipage form
Ive fixed that by adding
.when("/q2/:uid" in the routing:
.when("/q2/:uid", {
templateUrl: "partials/q2.html",
controller: 'formController',
paramExample: uid
})
And added this as a hidden field to pass params between webform pages
<< input type="hidden" required ng-model="formData.userid" ng-init="formData.userid=uid" />
Im new to Angular so not sure its the best possible solution but it seems to work ok for me now
Directly assign the value to model in data-ng-value attribute.
Since Angular interpreter doesn't recognize hidden fields as part of ngModel.
<input type="hidden" name="pfuserid" data-ng-value="newPortfolio.UserId = data.Id"/>
I use a classical javascript to set value to hidden input
$scope.SetPersonValue = function (PersonValue)
{
document.getElementById('TypeOfPerson').value = PersonValue;
if (PersonValue != 'person')
{
document.getElementById('Discount').checked = false;
$scope.isCollapsed = true;
}
else
{
$scope.isCollapsed = false;
}
}
Below Code will work for this IFF it in the same order as its mentionened
make sure you order is type then name, ng-model ng-init, value. thats It.
Here I would like to share my working code :
<input type="text" name="someData" ng-model="data" ng-init="data=2" style="display: none;"/>
OR
<input type="hidden" name="someData" ng-model="data" ng-init="data=2"/>
OR
<input type="hidden" name="someData" ng-init="data=2"/>

AngularJS: How do I manually set input to $valid in controller?

Using the TokenInput plugin and using AngularJS built-in formController validation.
Right now I'm trying to check if the field contains text, and then set field to valid if it does. The issue with using the plugin is it creates it's own input and then a ul+li for stlying.
I have access to addItem (formname) and my capablities in the controller, I just need to set it to $valid.
Markup.
<form class="form-horizontal add-inventory-item" name="addItem">
<input id="capabilities" name="capabilities" token-input data-ng-model="inventoryCapabilitiesAutoComplete" data-on-add="addCapability()" data-on-delete="removeCapability()" required>
<div class="required" data-ng-show="addItem.capabilities.$error.required" title="Please enter capability."></div>
</form>
JS.
$scope.capabilityValidation = function (capability) {
if (capability.name !== "") {
addItem.capabilities.$valid = true;
addItem.capabilities.$error.required = false;
} else {
addItem.capabilities.$valid = false;
addItem.capabilities.$error.required = true;
}
};
I'm running the capabilityValidation function when TokenInput has something entered and passing in the object.
EDIT:
Found out ng-model on my input does stuff and gets the autocomplete results, which is why I can't get ng-valid to work since it's based on the model.
$scope.inventoryCapabilitiesAutoComplete = {
options: {
tokenLimit: null
},
source: urlHelper.getAutoComplete('capability')
};
I didn't write this autocomplete implementation, is there another way to do this where I would have access to the ng-model attr and move the model function somewhere else?
You cannot directly change a form's validity. If all the descendant inputs are valid, the form is valid, if not, then it is not.
What you should do is to set the validity of the input element. Like so;
addItem.capabilities.$setValidity("youAreFat", false);
Now the input (and so the form) is invalid.
You can also see which error causes invalidation.
addItem.capabilities.errors.youAreFat == true;
The answers above didn't help me solve my problem. After a long search I bumped into this partial solution.
I've finally solved my problem with this code to set the input field manually to ng-invalid (to set to ng-valid set it to 'true'):
$scope.myForm.inputName.$setValidity('required', false);
I came across this post w/a similar issue.
My fix was to add a hidden field to hold my invalid state for me.
<input type="hidden" ng-model="vm.application.isValid" required="" />
In my case I had a nullable bool which a person had to select one of two different buttons. if they answer yes, an entity is added to the collection and the state of the button changes. Until all of the questions get answered, (one of the buttons in each of the pairs has a click) the form is not valid.
vm.hasHighSchool = function (attended) {
vm.application.hasHighSchool = attended;
applicationSvc.addSchool(attended, 1, vm.application);
}
<input type="hidden" ng-model="vm.application.hasHighSchool" required="" />
<div class="row">
<div class="col-lg-3"><label>Did You Attend High School?</label><label class="required" ng-hide="vm.application.hasHighSchool != undefined">*</label></div>
<div class="col-lg-2">
<button value="Yes" title="Yes" ng-click="vm.hasHighSchool(true)" class="btn btn-default" ng-class="{'btn-success': vm.application.hasHighSchool == true}">Yes</button>
<button value="No" title="No" ng-click="vm.hasHighSchool(false)" class="btn btn-default" ng-class="{'btn-success': vm.application.hasHighSchool == false}">No</button>
</div>
</div>
It is very simple. For example :
in you JS controller use this:
$scope.inputngmodel.$valid = false;
or
$scope.inputngmodel.$invalid = true;
or
$scope.formname.inputngmodel.$valid = false;
or
$scope.formname.inputngmodel.$invalid = true;
All works for me for different requirement. Hit up if this solve your problem.
to get this working for a date error I had to delete the error first before calling $setValidity for the form to be marked valid.
delete currentmodal.form.$error.date;
currentmodal.form.$setValidity('myDate', true);

Categories