Reputation: 3911
I'm using version 0.7.1 of angular material. I'm using the autocomplete as described here: Autocomplete demo
However, it doesn't seem to support validation logic, even though it generates a textarea: Autocomplete directive documentation
I imagine that I can add logic in the querySearch function to switch ng-valid to ng-invalid. Is this correct? If this is the case, then I need a handle on the md-autocomplete, but this is difficult, because the name attribute gets removed.
Upvotes: 9
Views: 19580
Reputation: 747
I was working with same approach with the form validation using auto-complete in angular materials.But unfortunately, validation on this directive is not so smooth as input components. So I made up my mind to overcome this issue and did some R&D for this component. Please find below code snippets and they will help you out on this.
HTML:
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak="" class="autocompletedemoBasicUsage" ng-app="MyApp">
<md-content class="md-padding">
<form ng-submit="$event.preventDefault()" name="registerForm" novalidate>
<p>Use <code>md-autocomplete</code> to search for matches from local or remote data sources.</p>
<md-autocomplete md-input-name="Country" ng-disabled="ctrl.isDisabled" md-no-cache="ctrl.noCache" md-selected-item="ctrl.selectedItem" md-search-text-change="ctrl.searchTextChange(ctrl.searchText)" md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)" md-items="item in ctrl.querySearch(ctrl.searchText)" md-item-text="item.display" md-min-length="0" placeholder="What is your favorite US state?" ng-class="{'validate': registerForm.Country.$touched && !vm.country1}">
<md-item-template>
<span md-highlight-text="ctrl.searchText" md-highlight-flags="^i">{{item}}</span>
</md-item-template>
<md-not-found>
No states matching "{{ctrl.searchText}}" were found.
<a ng-click="ctrl.newState(ctrl.searchText)">Create a new one!</a>
</md-not-found>
</md-autocomplete>
<div class="ng-message" ng-messages="registerForm.Country.$error" ng-show="registerForm.Country.$touched" role="alert">
<div class="validate" ng-show="registerForm.Country.$touched && ctrl.country1 == ''" ng-class="{'slide': registerForm.Country.$touched && ctrl.country1 == ''}">
<span>Country field is required</span>
</div>
<div class="validate" ng-show="ctrl.country1 == null" ng-class="{'slide': ctrl.country1 == null}">
<span>Please enter valid Country</span>
</div>
</div>
<br>
<md-button class="medium-button success-button" aria-label="submit" ng-disabled="registerForm.$invalid || registerForm.$pristine || !ctrl.country1" ng-click="ctrl.registerUser()">
Submit
</md-button>
</form>
</md-content>
</div>
SCRIPT:
(function () {
'use strict';
angular
.module('MyApp',['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl ($timeout, $q, $log) {
var self = this;
self.simulateQuery = false;
self.isDisabled = false;
// list of `state` value/display objects
self.states = loadAll();
self.querySearch = querySearch;
self.selectedItemChange = selectedItemChange;
self.searchTextChange = searchTextChange;
self.newState = newState;
function newState(state) {
alert("Sorry! You'll need to create a Constituion for " + state + " first!");
}
function querySearch (query) {
var results = query ? self.states.filter( createFilterFor(query) ) : self.states,
deferred;
if (self.simulateQuery) {
deferred = $q.defer();
$timeout(function () { deferred.resolve( results ); }, Math.random() * 1000, false);
return deferred.promise;
} else {
return results;
}
}
function searchTextChange(text) {
//$log.info('Text changed to ' + text);
if(text)
self.country1 = text.match(/^[a-zA-Z0-9\_\- ]*$/);
else
self.country1 = '';
if (text)
self.country = text;
$log.info('Item changed to ' + self.country1);
}
function selectedItemChange(item) {
if(item)
self.country1 = item.match(/^[a-zA-Z0-9\_\- ]*$/);
else
self.country1 = '';
if (item)
self.country = item;
$log.info('Item changed to ' + self.country1);
}
/**
* Build `states` list of key/value pairs
*/
function loadAll() {
var allStates = 'Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware,\
Florida, Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana,\
Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana,\
Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina,\
North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina,\
South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia,\
Wisconsin, Wyoming';
return allStates.split(/, +/g).map( function (state) {
return state;
});
}
/**
* Create filter function for a query string
*/
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(state) {
return (state.value.indexOf(lowercaseQuery) === 0);
};
}
}
})();
See the full example of codepen here
Upvotes: 1
Reputation: 2347
Quick update, got the solution on Angular Material site (Latest release 1.0.0-), https://material.angularjs.org/latest/demo/autocomplete.
You will find that 'required' and 'ng-messages' are supported now.
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak>
<md-content class="md-padding">
<form ng-submit="$event.preventDefault()" name="searchForm">
<p>The following example demonstrates floating labels being used as a normal form element.</p>
<div layout-gt-sm="row">
<md-input-container flex>
<label>Name</label>
<input type="text"/>
</md-input-container>
<md-autocomplete flex required
md-input-name="autocompleteField"
md-input-minlength="2"
md-input-maxlength="18"
md-no-cache="ctrl.noCache"
md-selected-item="ctrl.selectedItem"
md-search-text="ctrl.searchText"
md-items="item in ctrl.querySearch(ctrl.searchText)"
md-item-text="item.display"
md-floating-label="Favorite state">
<md-item-template>
<span md-highlight-text="ctrl.searchText">{{item.display}}</span>
</md-item-template>
<div ng-messages="searchForm.autocompleteField.$error" ng-if="searchForm.autocompleteField.$touched">
<div ng-message="required">You <b>must</b> have a favorite state.</div>
<div ng-message="minlength">Your entry is not long enough.</div>
<div ng-message="maxlength">Your entry is too long.</div>
</div>
</md-autocomplete>
</div>
</form>
Upvotes: 10
Reputation: 3787
you need these options
You can use above as below to run yr custom validation :
Update yr template as below
template:'<span ng-show="validationCheck">yr msg here</span><md-autocomplete\
md-no-cache="noCache"\
md-selected-item="selectedItem"\
md-search-text="searchText"\
md-items="item in querySearch(searchText)"\
md-item-text="item.display"\
placeholder="search query"\
md-selected-item-change="validate2(searchText)"\
md-search-text-change="validate(searchText)">\
<span md-highlight-text="searchText">{{item.display}}</span>\
</md-autocomplete>'
and add following yr md-auto-complate controller
$scope.validationCheck=false;
$scope.validate=function(data){
$scope.validationCheck=true;
console.log('validation : '+data);
}
$scope.validate2=function(data){
console.log('validation2 :'+data);
}
Upvotes: 1
Reputation: 3911
It seems that I am not the only one to find this tricky. There will be a solution to this soon: Autocomplete validation improvements in progress
Upvotes: 0