Reputation: 11
I am setting up custom template for md-select using custom directive but form validiation and required validiation is not working. This is for refactoring template of md-select using custom directive as md-custom-select.
I have created template of md-select in custom directive passing models and lists for dropdown and also required attr. The main problem for this custom directive is , it doesnot validiate form.
I am converting :
<md-select required ng-model="vm.Search.ParentDivisionID" ng-change="vm.GetDivisionIDList()">
<md-option ng-value="item.ID" ng-repeat="item in vm.ParentDivisionList">
{{item.Name}}
</md-option>
</md-select>
TO:
<md-custom-select ng-model="vm.Search.ParentDivisionID" list="vm.ParentDivisionList" ng-required="true" ng-change="vm.GetDivisionIDList(vm.Search.ParentDivisionID)"></md-custom-select>
(function () {
'use strict';
window.app.directive('mdCustomSelect', mdCustomSelect);
mdCustomSelect.$inject = ['$compile'];
function mdCustomSelect($compile) {
var styleTemplate = "<style>\
md-checkbox#checkAllBox{\
margin: 16px 0px 10px 5px;\
}\
md-checkbox#checkAllBox .md-label {\
margin-bottom: 0px !important;\
}\
md-checkbox#checkAllBox .md-label span {\
margin-left: 3px !important;\
}\
md-checkbox#checkAllBox .md-icon {\
height: 20px !important;\
width: 20px !important;\
}\
.parentLabel .parentLabel label {\
border-bottom: 1px solid #ccc;\
color: #000;\
padding-bottom: 6px;\
}\
md-checkbox#checkAllBox:not([disabled]).md-warn.md-checked .md-icon {\
background-color: rgb(88, 104, 191) !important;\
}\
md-checkbox#checkAllBox.md-checked .md-icon:after {\
height: 13px !important;\
left: 5px !important;\
}\
.parentLabel .md-container-ignore {\
padding: 0px;\
margin: 0px;\
border:none;\
}\
</style>";
var selectAllTemplate = '<div style="padding: 0px 0px 15px 5px; background-color: #efefef; border-bottom: 1px solid #ccc;">\
<md-checkbox aria-label="Parent Checkbox" class="md-warn" id="checkAllBox" title="Select All" ng-model="checkAllChecked" ng-change="toggleSelectAll()">Check/Uncheck All </md-checkbox>\
</div>';
function searchTemplate(placeholder) {
if (placeholder == undefined || placeholder == "") placeholder = "Search ...";
return '<md-select-header aria-label="Select Header" class="demo-select-header">\
<input aria-label="InputSearchBox" ng-keydown="$event.stopPropagation()" ng-model="searchTerm" type="search" placeholder="' + placeholder + '"\
class="demo-header-searchbox md-text">\
</md-select-header>';
}
function getOptionTemplate(isMultiple, isGroup) {
var optionTemplate = '<md-option aria-label="Dropdown Selector" ng-value="subItem.ItemID" ng-repeat="subItem in ' + (isGroup ? 'item.SubItems' : 'ItemList') + ' | filter: searchTerm">{{subItem.ItemName}}</md-option>';
if (isGroup == false) {
return (isMultiple ? selectAllTemplate : '') + optionTemplate;
}
return (isMultiple ? selectAllTemplate : '') + '<md-optgroup aria-label="Dropdown Selector" class="parentLabel" ng-repeat="item in ItemList">\
<div ' + (isMultiple ? 'ng-click="item.toggleSelect() "' : '') + 'style="padding:10px 10px 10px 10px; font-size:1.4em; color:black; border-bottom: 1px solid #ccc;">\
{{item.ItemName}}\
</div>'
+ optionTemplate +
'</md-optgroup>';
}
function getMdSelectOptionsTemplate($scope) {
var returnTemplate = $scope.isMultipleSelected ? 'multiple ' : '';
returnTemplate += 'ng-required="isRequired" ';
returnTemplate +='ng-disabled="isDisabled" ';
return returnTemplate;
}
var linker = function ($scope, element, attrs, controllers) {
//https://github.com/angular/angular/issues/10094 Binding required attribute always applies the required validator
$scope.isMultipleSelected = "multiple" in attrs ? (attrs.multiple == "false" ? false : true) : false;
$scope.isGroup = "group" in attrs ? (attrs.group == "false" ? false : true) : false;
$scope.ngModelCtrl = controllers.ngModelCtrl;
var ngModelName = attrs.ngModel;
var completeTemplate = "";
completeTemplate += styleTemplate;
//1 begin
completeTemplate += '<md-select ' + getMdSelectOptionsTemplate($scope) + 'ng-model="ngModel" md-on-open="mdOpen()" md-on-close="mdClose()" ng-change="valChanged()" data-md-container-class="selectdemoSelectHeader" class="md-no-asterisk">';
completeTemplate += searchTemplate(attrs.placeholder);//2 begin and end
completeTemplate += getOptionTemplate($scope.isMultipleSelected, $scope.isGroup); // 3 begin and end
completeTemplate += ' </md-select>';//1 end
element.html(completeTemplate);
$compile(element.contents())($scope);
};
return {
restrict: "E",
require: {
ngModelCtrl: '^ngModel'
},
scope: { // also uses multiple and group attribute
list: "=",
ngModel: "<",
mdOnClose: "&",
ngOption: "<",
mdChangeOnClose: "&", // event fire when selector is closes with changed value
isDisabled: "=ngDisabled",
isRequired: "=ngRequired",
placeholder: "@"
},
replace: true,
link: linker, // link is called after controller
controller: ['$scope', function ($scope) {
var defaultValueProperty = $scope.ngOption == undefined || $scope.ngOption.Value == undefined ? 'DivisionID' : $scope.ngOption.Value;
var defaultTextProperty = $scope.ngOption == undefined || $scope.ngOption.Text == undefined ? 'DivisionName' : $scope.ngOption.Text;
var defaultParentValueProperty = $scope.ngOption == undefined || $scope.ngOption.ParentValue == undefined ? 'ParentDivisionID' : $scope.ngOption.ParentValue;
var defaultParentTextProperty = $scope.ngOption == undefined || $scope.ngOption.ParentText == undefined ? 'ParentDivisionName' : $scope.ngOption.ParentText;
$scope.ItemList = [];
var rawItemList;
$scope.$watch('list', function (newValue, OldValue) {
formatListForView(newValue);
}, true);
$scope.toggleSelectAll = function () {
valueChanged = true;
if ($scope.checkAllChecked == false) {
$scope.ngModelCtrl.$setViewValue([]);
} else {
$scope.ngModelCtrl.$setViewValue(rawItemList.map(function (item) { return item[defaultValueProperty]; }));
}
};
function formatListForView(rawList) {
rawList = rawList == null || rawList == undefined ? [] : rawList;
rawItemList = rawList;
var parentList = [];
var idList = [];
// if no grouping then just return the modified itemlist
if ($scope.isGroup == false) {
$scope.ItemList = rawList.map(function (subItem) {
return {
ItemID: subItem[defaultValueProperty],
ItemName: subItem[defaultTextProperty]
}
});
return; // below code is for grouping, not needed for group==false
}
// fill parent
rawList.forEach(function (item, index) {
if ((item[defaultParentValueProperty] != null || item[defaultParentValueProperty] != 0) && idList.indexOf(item[defaultParentValueProperty]) == -1) {
idList.push(item[defaultParentValueProperty]);
parentList.push({
ItemID: item[defaultParentValueProperty],
ItemName: item[defaultParentTextProperty]
});
}
});
// fill children
parentList.forEach(function (item, index) {
item.SubItems = rawList.filter(function (subitem) {
return subitem[defaultParentValueProperty] == item.ItemID;
}).map(function (subItem) {
return {
ItemID: subItem[defaultValueProperty],
ItemName: subItem[defaultTextProperty]
}
});
// toggle children from parent
item.toggleSelect = function () {
var valuesToToggle = item.SubItems.map(function (item) {
return item.ItemID;
});
valueChanged = true;
var alreadySelected = _.intersection(valuesToToggle, $scope.ngModel);
if (alreadySelected.length == 0 || (alreadySelected.length > 0 && alreadySelected.length != valuesToToggle.length)) { // select all from the parent
$scope.ngModelCtrl.$setViewValue(_.union(valuesToToggle, $scope.ngModel));
} else { // select none from the parent
$scope.ngModelCtrl.$setViewValue(_.difference($scope.ngModel, valuesToToggle));
}
}
});
$scope.ItemList = parentList;
}
var valueChanged = false; // check if value changed for ngChangeOnClose
$scope.valChanged = function () {
valueChanged = true;
// for ng-change
$scope.ngModelCtrl.$setViewValue($scope.ngModel);
}
$scope.mdOpen = function () {
valueChanged = false;
}
$scope.mdClose = function () {
if (typeof $scope.mdOnClose === 'function') $scope.mdOnClose();
if (valueChanged) {
if (typeof $scope.mdChangeOnClose === 'function') $scope.mdChangeOnClose();
}
}
}]
}
}
})();
My expected result from this is it should work for form validiation.
Upvotes: 1
Views: 182