What Is #Auto Attribute Here and Why It Is Required

What is #auto attribute here and why it is required

It is a template reference variable that allows us to get reference to html element or something else if we declare directive on this element.

We can declare template reference variable via (1)

  • #var
  • ref-var

#Default behavior

In most cases, Angular sets the reference variable's value to the html element on which it was declared (2) .

<div #divElem></div>
<input #inputEl>
<table #tableEl></table>
<form #formEl></form>

In the preceding all template reference variables will refer to the corresponding elements.

#divElem     HTMLDivElement
#inputEl HTMLInputElement
#tableEl HTMLTableElement
#formEl HTMLFormElement

#Directives can change default behavior

But a directive can change that behavior and set the value to something else, such as itself.

Angular assigns references with empty value to component (3)

If we have component like:

@Component({
selector: '[comp]',
...
})
export class SomeComponent {}

and template as:

<div comp #someComp></div>

then #someComp variable will refer to component itself (SomeComponent instance).

Angular doesn't locate directives in references with empty value (4)

If we change @Component decorator to @Directive

@Directive({
selector: '[comp]',
...
})
export class SomeDirective {}

then #someComp variable will refer to HTMLDivElement.

How we can get SomeDirective instance in this case?

Fortunately, Template reference variable can have value (5)

  • #var="exportAsValue"

  • ref-var="exportAsValue"

We can define exportAs property within @Component/@Directive decorator (6):

exportAs is a name under which the component instance is exported in a
template. Can be given a single name or a comma-delimited list of
names.

@Directive({
selector: '[comp]',
exportAs: 'someDir',
...
})
export class SomeDirective {}

and then use exportAs value as value for template reference variable within template (7):

<div comp #someComp="someDir"></div>

After that #someComp will refer to our directive.

Now let's imagine we have several directives applied to this component. And we want to get specific directive instance.exportAs property is a good choice to solve this problem.


Let's go back to your code

If you open source code of MdAutocomplete component you can see:

@Component({
...
exportAs: 'mdAutocomplete'
})
export class MdAutocomplete {
...

Since in your template you have

#auto="mdAutocomplete"

Then #auto variable will refer to instance of MdAutocomplete component. This reference is used in MdAutocompleteTrigger directive:

@Directive({
selector: 'input[mdAutocomplete], input[matAutocomplete],' +
'textarea[mdAutocomplete], textarea[matAutocomplete]',
...
})
export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
@Input('mdAutocomplete') autocomplete: MdAutocomplete;

because you're passing auto variable to input within template

<input mdInput placeholder="State" [mdAutocomplete]="auto"

We can omit value and use only variable name in this case like

<md-autocomplete #auto>

but

  • assignment value to value of exportAs property precisely indicates us where to get the instance.

  • if md-autocomplete is a directive then auto variable will refer to HTMLElement.

So prefer specifying value for template reference variable if you doubt what it will refer to.

Auto complete input field mandatory in form

Try this working demo :

var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) { $scope.create = function() { console.log("submitting.."); }});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script><div ng-app="myApp" ng-controller="MyCtrl">    <form name="addressform" ng-submit="addressform.$valid && create()" novalidate>        <span ng-show="submitted == true && addressform.address.$error.required">Required field.</span>        <div class="form-group">            <input type="text" name="address" id="LocationAutocomplete" class="form-control" ng-autocomplete="result1" ng-model="addressTemp" required/>        </div>    <div class="form-group">       <input type="submit" value="create" class="btn btn-primary btn-block" ng-click="submitted = true">    </div> </form></div>

Input elements should have autocomplete attributes

Try changing

<input type="password" name="password">

to

<input type="password" name="password" autocomplete="on">

Autocomplete lets web developers specify what (if any) permission the user agent has to provide automated assistance in filling out form field values, as well as guidance to the browser as to the type of information expected in the field.

It's pretty powerful.

Bad value for attribute autofocus

According to the specs, the autofocus attribute is a boolean attribute:

A number of attributes are boolean attributes. The presence of a
boolean attribute on an element represents the true value, and the
absence of the attribute represents the false value.

If the attribute is present, its value must either be the empty string
or a value that is an ASCII case-insensitive match for the attribute's
canonical name, with no leading or trailing whitespace.

The values "true" and "false" are not allowed on boolean attributes.
To represent a false value, the attribute has to be omitted
altogether.

The last paragraph pretty much explains why the validator is complaining.

In other words, you can replace

<div class="auth-reg-code-block" ng-if="regCodeRequired">
<input class="form-control" type="text" name="regCode"
id="regCode" ng-model="user.regCode" autofocus="{{regCodeRequired}}"
placeholder="Registration Code" required>
</div>

with:

<div class="auth-reg-code-block" ng-if="regCodeRequired">
<input class="form-control" type="text" name="regCode"
id="regCode" ng-model="user.regCode" autofocus
placeholder="Registration Code" required>
</div>

You might be interested in ng-autofocus plugin.

Missing autofillHints attribute

Perhaps you are using an EditText. autofillHints is used in API 26 and above for filling empty EditTexts and it's actually suggesting which type of content should be placed in there.

Just add :

android:autofillHints="username" // the type of content you want

To your EditText and warning will disappear.

You do this using the new android:autofillHints attribute to tell
autofill what type of content you expect, and
android:importantForAutofill to tell autofill which views you want (or
do not want) to be filled.

Read: https://medium.com/@bherbst/getting-androids-autofill-to-work-for-you-21435debea1

And this: https://developer.android.com/guide/topics/text/autofill-services


Edit:

You can however set:

android:importantForAutofill="no"

To the component to tell it is not important to fill and get rid of the error.

What should I do if I don't want to set the required attribute for some of my HTML input tags inside a form?

You can make it only apply :valid selector to elements with required attribute: input[required]:valid

For other fields a trick can be used to apply style if its not empty by adding an empty placeholder=" " attribute and the check if it's displayed or not via :placeholder-shown selector:

:root
{
--our-purple-color: purple;
background-color: black;
}
.Comment-rows {
position: relative;
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(161px, 1fr));
/* opacity: 0;*/
transform: translateY(20px);
transition: opacity 400ms ease-in, transform 300ms ease-in;
}

.Comment-rows .Comment-form {
position: relative;
width: 100%;
padding: 0 10px;
margin: 60px 0 10px;
transition: .5s;
}

.Comment-rows .Comment-form .Comment-InputBox {
position: relative;
width: 100%;
height: 40px;
color: yellow;
}

.Comment-rows .Comment-form .Comment-InputBox input,
.Comment-rows .Comment-form .Comment-InputBox.textarea textarea {
position: absolute;
width: 100%;
height: 100%;
background: transparent;
box-shadow: none;
border: none;
outline: none;
font-size: 1.8rem;
padding: 0 10px;
z-index: 1;
color: var(--our-purple-color);
}

.Comment-rows .Comment-form .Comment-InputBox .Comment-text {
position: absolute;
top: 0;
right: 0;
line-height: 40px;
font-size: 1.5rem;
padding: 0 10px;
display: block;
transition: .5s;
pointer-events: none;
}

/* added */
.Comment-rows .Comment-form .Comment-InputBox input:not([required]):not(:placeholder-shown)+.Comment-text,

.Comment-rows .Comment-form .Comment-InputBox input:focus+.Comment-text,
/* changed */
.Comment-rows .Comment-form .Comment-InputBox input[required]:valid+.Comment-text {
top: -35px;
right: -10px;
}

.Comment-rows .Comment-form .Comment-InputBox .Comment-Line {
position: absolute;
bottom: 0;
display: block;
width: 100%;
height: 2px;
background: yellow;
transition: .5s;
border-radius: 2px;
pointer-events: none;
}

/* added */
.Comment-rows .Comment-form .Comment-InputBox input:not([required]):not(:placeholder-shown)~.Comment-Line,

.Comment-rows .Comment-form .Comment-InputBox input:focus~.Comment-Line,
/* changed */
.Comment-rows .Comment-form .Comment-InputBox input[required]:valid~.Comment-Line {
height: 100%;
}

/*textarea*/

.Comment-rows .Comment-form .Comment-InputBox.textarea {
width: 100%;
height: 100px;
position: relative;
padding: 10px 0;
}

.Comment-rows .Comment-form .Comment-InputBox.textarea textarea {
height: 100%;
resize: none;
top: 0;
left: 0;
}

/* added */
.Comment-rows .Comment-form .Comment-InputBox textarea:not([required]):not(:placeholder-shown)+.Comment-text,

.Comment-rows .Comment-form .Comment-InputBox textarea:focus+.Comment-text,
/* changed */
.Comment-rows .Comment-form .Comment-InputBox textarea[required]:valid+.Comment-text {
top: -35px;
left: -10px;
}

/* added */
.Comment-rows .Comment-form .Comment-InputBox textarea:not([required]):not(:placeholder-shown)~.Comment-line,

.Comment-rows .Comment-form .Comment-InputBox textarea:focus~.Comment-Line,
/* changed */
.Comment-rows .Comment-form .Comment-InputBox textarea[required]:valid~.Comment-Line {
height: 100%;
}
<form autocomplete="off">
<div class="Comment-rows">
<div class="Comment-form">
<div class="Comment-InputBox">
<input type="text" name="name" autocomplete="nope" placeholder=" ">
<span class="Comment-text">name</span>
<span class="Comment-Line"></span>
</div>
</div>
<div class="Comment-form">
<div class="Comment-InputBox">
<input type="text" name="lastName" placeholder=" ">
<span class="Comment-text">last name</span>
<span class="Comment-Line"></span>
</div>
</div>
</div>

<div class="Comment-rows">
<div class="Comment-form">
<div class="Comment-InputBox">
<input type="email" name="email" required="required" autocomplete="on" oninvalid="this.setCustomValidity('')" oninput="this.setCustomValidity('')">
<span class="Comment-text">email*</span>
<span class="Comment-Line"></span>
</div>
</div>
<div class="Comment-form">
<div class="Comment-InputBox">
<input type="text" name="phoneNumber" placeholder=" ">
<span class="Comment-text">phone number</span>
<span class="Comment-Line"></span>
</div>
</div>
</div>

<div class="Comment-rows">
<div class="Comment-form">
<div class="Comment-InputBox textarea">
<textarea required="required" name="message" oninvalid="this.setCustomValidity('')" oninput="this.setCustomValidity('')"></textarea>
<span class="Comment-text">enter your message*</span>
<span class="Comment-Line"></span>
</div>
</div>
</div>

<div class="Comment-form-Button">
<button type="submit" disabled>
<span>send</span>
<div class="liquid"></div>
</button>
</div>
</form>

How exactly works ngModel directive in this use case?

NgModel directive creates a FormControl instance from a domain model and binds it to a form control element. That's right.

In all examples below NgModel directive is applied to input element.

<input name="name" ngModel>

<input name="name" [ngModel]="someValue">

<input name="name" [(ngModel)]="someValue">

It means that for each element above Angular will create an instance of NgModel class.

Internally this class holds a new instance of FormControl

 public readonly control: FormControl = new FormControl(); 

which value is updated and synced subsequently with model, input element and the rest form if needed .

Next thing you need to understand is template reference variable(#var)

This variable helps us to get hold of reference to some instance: either HTMLElement or Angular Component/Directive/Service.

Template reference variable can have a value #var="exportAsValue". This allows us to get reference to specific instance, e.g. we added to directives to an elements and want our template reference variable to refer to the first directive.

For this case we need to define exportAs property in @Directive decorator definition:

@Directive({
selector: '[myDir]',
exportAs: 'myCoolDir'
})
export class MyDir {
someProp: string;
}

Now, we can get reference to MyDir instance by using the following snippet:

<div myDir #someRef="myCoolDir">
{{ someRef.someProp }}

Back to your example:

  • #form="ngForm" holds a reference to NgForm class

  • #nameCtrl="ngModel" holds a reference to NgModel class

This means that you can access to any properties/methods of those classes like nameCtrl.invalid or form.invalid

See also:

  • What is #auto attribute here and why it is required

Ant Design- autocomplete need to not show value

If it was a select, you could use optionLabelProp to change the displayed prop. (link)

But in autocomplete, you can't change the displayed property. But, you can adopt with it. change the value: id to key: id and set the value to Title.

const searchResults = async query => {
return [
{
key: id,
value: Title,
label: DisplayElement(query, Title, info)
}
];
};

then you can access the key (the id) in onSelect like this:

const onSelect = (value, option) => {
// you don't want the value, instead you want the key.
console.log(option.key);
};

This way you display the right value to user, and also you can access the id when user selects it.



Related Topics



Leave a reply



Submit