I'm using angular2 inbuilt pipe percent in my HTML
<input class="ibox1 rightalign" type="text" [ngModel]="_note.StudentPercent| percent:'.5-5'" ngControl="StudentPercent" pattern="^[0-9]\d*(\.\d+)?$" #StudentPercent="ngForm">
its working & display correct data to input box, but when I change the value of a field pipe doesn't work.
How to resolve this?
You have reapply filter on your model value on change of _note.StudentPercent input. You could use ngModelChange handler for the same.
<input class="ibox1 rightalign" type="text"
[ngModel]="_note.StudentPercent| percent:'.5-5'"
(ngModelChange)="changeToPercent(_note.StudentPercent,'.5-5')"
ngControl="StudentPercent" pattern="^[0-9]\d*(\.\d+)?$"
#StudentPercent="ngForm" />
Code
changeToPercent(percent, format){
//make sure PercentPipe in declarations & providers of NgModule
this._note.StudentPercent = new PercentPipe().transform(percent, format)
}
Related
Accessibility guidelines were invented before components were released, so they always say that a label is used to identify a form control like <input> or <textarea>, etc. What happens when I have a complex Angular / React / ... component that acts like a form control?
Imagine a <custom-select> that renders an input and adds items to a list. The resulting html looks like:
<custom-select ....>
<input ...>
</custom-select>
When I type something in the input and I press enter, it adds that entry to the list and renders the input again, something like:
<custom-select ....>
<span>What I typed</span>
<input ...>
</custom-select>
Of course, if I type something else in the input and I press enter, it gets added to the list:
<custom-select ....>
<span>What I typed</span>
<span>Something else</span>
<input ...>
</custom-select>
If we want to use this custom component in a form, we would like to put a label to it like any other form item, p.e:
<label for="foo">Foo</label>
<input id="foo" type="text">
<label for="select">Select a country</label>
<custom-select id="select"></custom-select>
Is this even valid a11y? Wave tool will complain of an orphan label while axe says nothing. So, can we use a plain old label to tag a custom component for accessibility purposes? We need a label to be put there for consistency but needs to be accessible.
In case I can do this, that custom-select is also rendering an input. That input needs its own label or aria-label, right?
Yes the input will need to be labeled.
Is there any reason for the component to not manage this? Accept the labeling text and then render the correct accessible HTML for the label and input pair?
So in React:
<CustomSelect labelText="Enter your destination" />
with the component doing:
const id = generatedUniqueId() // This will need to be memoized in the real implementation to avoid creating new id's with every render.
...
<>
<label for={id}>{labelText}</label>
<input id={id} />
</>
Atleast in angular: You can preserve a11y like the following:
// Custom Input HTML (Using Angular Material for eg);
// You can import the label inside the custom component and bind it to the
input field so that you can always have a new ID to every custom input
<mat-form-field [attr.aria-labelledby]="customAriaLabelledByIDs">
<mat-label *ngIf="label" [for]="customId">{{ label }}</mat-label>
<input matInput [id]="customId" />
</mat-form-field>
// In your component.ts file,
#Input() customId: string;
#Input() customAriaLabelledByIDs: string[];
combinedAriaLabelledByIDs: string;
ngOnInit() {
if (this.customAriaLabelledByIDs) {
this.combinedAriaLabelledByIDs =
this.customAriaLabelledByIDs.length === 1
? this.customAriaLabelledByIDs[0]
: this.customAriaLabelledByIDs.join(' ');
}
}
/// Wherever you use, now you will have something like this:
<your-custom-selector
[customAriaLabelledByIDs]="['id-1', 'id-2', 'id-3']"
[customId]="first-name-ID"
></your-custom-selector>
<your-custom-selector
[customAriaLabelledByIDs]="['id-4', 'id-5', 'id-6']"
[customId]="second-name-ID"
></your-custom-selector>
etc.,
You can add multiple aria-attributes to the #Input() and use it from the custom component like, aria-label, role, aria-expanded, etc...
Let me know if you need any more explanation on any of the things i mentioned above. Will be happy to help!!
i have an Angular Factory that gets a single date from the backend of my spring application, and i wanted to add it to an Input so the calendar input is always set with the date obtained from the backend, without the possibility for the user to change it. How could i achieve this? Should i put it on my controller or directly on the button? This is my code:
Factory(concatenated with other .factory):
.factory('DataInizioGeneraCalendario', function ($resource) {
return $resource('rest/anagrafica/dataInizioGeneraCalendario', {
get: {
method: 'GET'
}
});
Controller Function:
$scope.generaCalendario = function () {
$scope.modificaCalendarioDiv = true;
$scope.successMessage = false;
$("#idModificaCalendarioDiv").hide();
$scope.element = new Calendario();
autoScroll('generaCalendario');
$("#idErrorTemplate").hide();
$('#data').attr('disabled', false);
$("#idGeneraCalendarioDiv").show();
};
Input :
<div class="col-xs-12 col-md-2" >
<label for="dataInizio" class="row col-xs-12 control-label" style="text-align: left">da Data</label>
<input class="datepicker form-control" placeholder="gg/mm/aaaa" required type="text" id="data" ng-disabled="true" />
</div>
Edit : forgot to add, the controller function is called by the button that displays the input for the calendar.
Because your factory's GET request will return the date value asynchronously, it's better to have a $scope.date in your controller that will hold the date value that is returned from the server. Also, depending on the format in which you store dates on the backend, you might need to transform the value that is returned from the backend into the string format, so it would be properly consumed by the <input type="date"> as per Angular docs.
In your code, you need to bind the input element to this value, like this: <input ng-model="date">.
What it will do is bind this input to the data model, so that every time when user edits the input the $scope.date would be updated too.
If you do not want users to be able to edit this date, then you need to:
Keep the input field disabled <input disabled> (no need to use ng-disabled here, because you want to keep it always disabled). And also remove this line: $('#data').attr('disabled', false); in your function.
You the one-way binding, instead of two0way binding, like this: <input disabled ng-value="date">
Here is the working DEMO that shows two inputs: one that is editable and another that is not.
I have here a html text box. It has an ng-model and an initial value on it. The problem is the initial value is not shown when there's an ng-model present and I need both of the ng-model and the initial value for the textbox.
HTML:
<input type="text"
ng-model="selPcode"
name="missionId"
value="123">
JS:
$scope.setPcode = function(site){
$scope.selPcode = site.id};
Can anyone suggest a way how to make the value show in the text box and keep the ng-model present? Thanks in advance.
Set an initial value to the ng-model on your controller's scope. Something like $scope.selPcode = 123. Set it to what your value would have been. That way, it'll display initially and then you can also change it.
Well, Angular works with two-way data binding, so why not simply set the initial value in your controller?
$scope.selPcode = 123;
This way, you'll see it in your input.
Use ng-init without having to touch the controller and keep the code in the HTML readable, like you would with the value= syntax for the standard use of the Inputbox. Plunkr here
Example Here (Controller As Syntax):
<div ng-controller="myController as my">
<h1>Hello {{my.name}}</h1>
<input type="text"
ng-init="my.selPcode=123"
ng-model="my.selPcode"
name="missionId">
</div>
Controller:
myApp.controller('myController', function($scope) {
this.name = "Gene";
});
<paper-input
id="server"
floatinglabel=""
label="Server Address"
value=""
required
type="URL">
</paper-input>
the example above worked until the latest polymer update now even the required attribute does nothing. was there some change to core-input that i am missing in documentation? all my inputs with patterns, numbers, urls, or emails nothing causes it to get the invalid class.
<paper-input-decorator
id="address"
labelVisible
floatinglabel
error="URL Required"
label="Server Address">
<input is="core-input" type="URL" id="server" required>
</paper-input-decorator>
above is the updated markup for checking input of url. before the changes the input had invalid by default cause the field was required and updated as you type.
with the new changes you have to call a function to get the input to return the invalid class. (you could put a event listener on the input and run that function every time the input is updated. but i only check on attempted submission) to check i put all the inputs i want to check in a container (a div with a id) then when user click to submit i run the function below.
validate: function (id) {
'use strict';
var $d = document.getElementById(id).querySelectorAll('paper-input-decorator');
Array.prototype.forEach.call($d, function(d) {
d.isInvalid = !d.querySelector('input').validity.valid;
});
}
and pass in the id of the input container. validate(id);
that will cause the input to display the invalid class if input doesn't meet type / pattern requirement. you can then check for invalid class in the same method as before.
invalid = document.querySelector("#address").classList.contains("invalid");
outside a custom element or
invalid = this.$.address.classList.contains("invalid");
inside custom element
then some logic to check for invalid class before running the save function
if (!invalid) {
save();
}
also keep in mind that the decorator and input both have a id. the id on the decorator is used to check for validity while the id on the input is there for getting the value from the committedValue attribute.
info above is for the master branch pulled after 10 - 16 - 14
I have several <input> fields within a <form>. Angular takes the value from those fields regardless of the <form> (which is actually there only for Bootstrap to apply the right styles to inner fields).
Now, I want to be able to reset the fields, and so get Angular update the output associated to them as well. However, a regular <input type="reset"/> button is not working. It resets the values of all the <input> fields, but Angular is not refreshing the output that is based on the fields after it.
Is there any way to tell Angular to refresh the outputs based on the current state of the fields? Something like a ng-click="refresh()"?
Let's say you have your model called address. You have this HTML form.
<input [...] ng-model="address.name" />
<input [...] ng-model="address.street" />
<input [...] ng-model="address.postalCode" />
<input [...] ng-model="address.town" />
<input [...] ng-model="address.country" />
And you have this in your angular controller.
$scope.reset = function() {
$scope.defaultAddress = {};
$scope.resetAddress = function() {
$scope.address = angular.copy($scope.defaultAddress);
}
};
JSFiddle available here.
You should have your values tied to a model.
<input ng-model="myvalue">
Output: {{myvalue}}
$scope.refresh = function(){
delete $scope.myvalue;
}
JSFiddle: http://jsfiddle.net/V2LAv/
Also check out an example usage of $pristine here:
http://plnkr.co/edit/815Bml?p=preview