Merge "Provide 'validatable-with' directive"
This commit is contained in:
commit
f0023b100f
|
@ -559,7 +559,12 @@
|
||||||
'index': 0,
|
'index': 0,
|
||||||
'panelIndex': 0,
|
'panelIndex': 0,
|
||||||
'row': 0
|
'row': 0
|
||||||
}
|
},
|
||||||
|
'@constraints': [
|
||||||
|
function(value) {
|
||||||
|
return value !== 'workbook1' ? true : 'The sample validation failure.';
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'description': {
|
'description': {
|
||||||
|
|
|
@ -112,6 +112,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.directive('validatableWith', function($parse) {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function(scope, element, attrs, ctrl) {
|
||||||
|
var model;
|
||||||
|
if ( attrs.validatableWith ) {
|
||||||
|
model = $parse(attrs.validatableWith)(scope);
|
||||||
|
scope.error = '';
|
||||||
|
model.setValidatable && model.setValidatable(true);
|
||||||
|
model.on && model.on('validation', function(result) {
|
||||||
|
var isValid = (result == 'succeeded'),
|
||||||
|
baseMessage = '';
|
||||||
|
// (FIXME): hack until Barricade supports validation of empty required entries
|
||||||
|
if ( !model.get() && model.isRequired() ) {
|
||||||
|
isValid = false;
|
||||||
|
baseMessage = 'This field is required.'
|
||||||
|
}
|
||||||
|
ctrl.$setValidity('barricade', isValid);
|
||||||
|
scope.error = model.hasError() ? model.getError() : baseMessage;
|
||||||
|
});
|
||||||
|
ctrl.$formatters.push(function(modelValue) {
|
||||||
|
return modelValue === undefined ?
|
||||||
|
( ctrl.$isEmpty(ctrl.$viewValue) ? undefined : ctrl.$viewValue ) :
|
||||||
|
modelValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.directive('typedField', ['$compile', 'merlin.templates',
|
.directive('typedField', ['$compile', 'merlin.templates',
|
||||||
function($compile, templates) {
|
function($compile, templates) {
|
||||||
function updateAutoCompletionDirective(template) {
|
function updateAutoCompletionDirective(template) {
|
||||||
|
|
|
@ -32,11 +32,18 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
var modelMixin = Barricade.Blueprint.create(function(type) {
|
var modelMixin = Barricade.Blueprint.create(function(type) {
|
||||||
|
var isValid = true,
|
||||||
|
isValidatable = false;
|
||||||
this.value = function() {
|
this.value = function() {
|
||||||
if ( !arguments.length ) {
|
if ( !arguments.length ) {
|
||||||
return this.get();
|
if ( isValidatable ) {
|
||||||
|
return isValid ? this.get() : undefined;
|
||||||
|
} else {
|
||||||
|
return this.get();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.set(arguments[0]);
|
this.set(arguments[0]);
|
||||||
|
isValid = !this.hasError();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.id = utils.getNewId();
|
this.id = utils.getNewId();
|
||||||
|
@ -45,6 +52,10 @@
|
||||||
return type;
|
return type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.setValidatable = function(validatable) {
|
||||||
|
isValidatable = validatable;
|
||||||
|
};
|
||||||
|
|
||||||
this.setType = function(_type) {
|
this.setType = function(_type) {
|
||||||
type = _type;
|
type = _type;
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,8 +54,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editable .fa-pencil {
|
editable {
|
||||||
color: black;
|
.fa-pencil {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
button:disabled {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
</span>
|
</span>
|
||||||
<span ng-show="isEdited">
|
<span ng-show="isEdited">
|
||||||
<input type="text" ng-model="editableValue" show-focus="isEdited">
|
<input type="text" ng-model="editableValue" show-focus="isEdited">
|
||||||
<button ng-click="accept()"><i class="fa fa-check"></i></button>
|
<button ng-click="accept()" ng-disabled="!editableValue"><i class="fa fa-check"></i></button>
|
||||||
<button ng-click="reject()"><i class="fa fa-close"></i></button>
|
<button ng-click="reject()"><i class="fa fa-close"></i></button>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
||||||
<input type="number" class="form-control" id="elem-{$ $id $}"
|
<input type="number" class="form-control" id="elem-{$ $id $}"
|
||||||
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
||||||
autocompletable="true">
|
autocompletable="true" validatable-with="value">
|
||||||
|
<div ng-show="error" class="alert alert-danger">{$ error $}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
||||||
<input type="text" class="form-control" id="elem-{$ $id $}"
|
<input type="text" class="form-control" id="elem-{$ $id $}"
|
||||||
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
||||||
autocompletable="true">
|
autocompletable="true" validatable-with="value">
|
||||||
|
<div ng-show="error" class="alert alert-danger">{$ error $}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
<label for="elem-{$ $id $}">{$ value.title() $}</label>
|
||||||
<textarea class="form-control" id="elem-{$ $id $}"
|
<textarea class="form-control" id="elem-{$ $id $}"
|
||||||
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
ng-model="value.value" ng-model-options="{ getterSetter: true }"
|
||||||
autocompletable="true"></textarea>
|
autocompletable="true" validatable-with="value"></textarea>
|
||||||
|
<div ng-show="error" class="alert alert-danger">{$ error $}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -347,4 +347,83 @@ describe('merlin directives', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("'validatable'", function() {
|
||||||
|
var fields;
|
||||||
|
|
||||||
|
beforeEach(inject(function($injector) {
|
||||||
|
fields = $injector.get('merlin.field.models');
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('working with the @constraints property:', function() {
|
||||||
|
var model, elt,
|
||||||
|
goodValue = 'allowedValue',
|
||||||
|
badValue = 'restrictedValue',
|
||||||
|
errorMessage = 'Wrong value provided';
|
||||||
|
beforeEach(function() {
|
||||||
|
var modelClass = fields.string.extend({}, {
|
||||||
|
'@constraints': [
|
||||||
|
function(value) {
|
||||||
|
return value !== badValue ? true : errorMessage;
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
$scope.model = modelClass.create();
|
||||||
|
elt = $compile('<form name="form"><input name="model" type="text" ' +
|
||||||
|
'ng-model="model.value" ng-model-options="{ getterSetter: true }" ' +
|
||||||
|
'validatable-with="model"></form>')($scope);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('any valid value', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
$scope.form.model.$setViewValue(goodValue);
|
||||||
|
$scope.$digest();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is allowed to be entered', function() {
|
||||||
|
expect($scope.form.model.$viewValue).toEqual(goodValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is propagated into the model', function() {
|
||||||
|
expect($scope.model.value()).toEqual(goodValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not cause the input to be marked as erroneous', function() {
|
||||||
|
expect(elt.find('input').hasClass('ng-valid')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets error message on scope to an empty string', function() {
|
||||||
|
expect($scope.error).toEqual('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('any invalid value', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
$scope.form.model.$setViewValue(badValue);
|
||||||
|
$scope.$digest();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is allowed to be entered', function() {
|
||||||
|
expect($scope.form.model.$viewValue).toEqual(badValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is not propagated into the model', function() {
|
||||||
|
expect($scope.model.value()).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('causes the input to be marked as erroneous', function() {
|
||||||
|
expect(elt.find('input').hasClass('ng-invalid')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exposes error message in the parent scope', function() {
|
||||||
|
expect($scope.error).toEqual(errorMessage);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('working with the @required property', function() {
|
||||||
|
// TODO: fill in once validation of @required fields changes in Barricade
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue