diff --git a/src/components/textField/textField.js b/src/components/textField/textField.js index 78b0636e08a..f119a71f91e 100644 --- a/src/components/textField/textField.js +++ b/src/components/textField/textField.js @@ -4,7 +4,7 @@ * @description * Form */ -angular.module('material.components.textField', ['material.core']) +angular.module('material.components.textField', ['material.core', 'material.services.theming']) .directive('mdInputGroup', [ mdInputGroupDirective ]) .directive('mdInput', ['$mdUtil', mdInputDirective ]) .directive('mdTextFloat', [ '$mdTheming', mdTextFloatDirective ]); @@ -42,6 +42,7 @@ function mdTextFloatDirective($mdTheming) { replace: true, scope : { fid : '@?', + label : '@?', value : '=ngModel' }, compile : function() { @@ -53,21 +54,23 @@ function mdTextFloatDirective($mdTheming) { scope.isDisabled = true; } - // transpose the `label` value - scope.label = attrs.label || ""; + // transpose the `label`, type, and fid properties scope.fid = scope.fid || scope.label; + scope.inputType = attrs.type || "text"; + element.removeAttr('type'); + // transpose optional `type` and `class` settings - element.attr('type', attrs.type || "text"); element.attr('class', attrs.class ); + }, post: $mdTheming }; }, template: '' + - ' ' + - ' ' + + ' ' + + ' ' + '' }; } diff --git a/src/components/textField/textField.spec.js b/src/components/textField/textField.spec.js index 348e2344de7..c974689f3fb 100644 --- a/src/components/textField/textField.spec.js +++ b/src/components/textField/textField.spec.js @@ -1,44 +1,257 @@ -xdescribe('mdInputGroup directive', function() { +describe('Text Field directives', function() { beforeEach(module('material.components.textField')); - function setup(inputAttrs) { + describe('- mdInputGroup', function() { + var scope; + + beforeEach(function() { + scope = { + user : { + firstName: 'Thomas', + lastName: 'Burleson', + email: 'ThomasBurleson@gmail.com', + password: 'your password is incorrect' + } + } + }); + + it('should set input class for focus & blur', function() { + var expressions = {label:"Firstname", model:"user.firstName"}, + el = setupInputGroup( expressions, scope), + input = el.find('input'); + + input.triggerHandler('focus'); + expect(el.hasClass('md-input-focused')).toBe(true); + input.triggerHandler('blur'); + expect(el.hasClass('md-input-focused')).toBe(false); + }); + + it('should set input class for input event', function() { + var expressions = {label:"email", model:"user.email", type:"email"}, + el = setupInputGroup( expressions, scope), + input = el.find('input'); + + expect(el.hasClass('md-input-has-value')).toBe(true); + + input.val(''); + input.triggerHandler('input'); + expect(el.hasClass('md-input-has-value')).toBe(false); + + input.val('ThomasBurleson@gmail.com'); + input.triggerHandler('input'); + expect(el.hasClass('md-input-has-value')).toBe(true); + }); + + it('should set input class for ngModel render', function() { + var expressions = {label:"Firstname", model:"user.firstName"}, + el = setupInputGroup( expressions, scope), + input = el.find('input'); + + expect(el.hasClass('md-input-has-value')).toBe(true); + + input.scope().$apply('user.firstName = ""'); + expect(el.hasClass('md-input-has-value')).toBe(false); + + input.scope().$apply('user.firstName = "Thomas"'); + expect(el.hasClass('md-input-has-value')).toBe(true); + }); + + }); + + describe(' - mdTextFloat', function() { + var model; + beforeEach(function() { + model = { + labels : { + firstName: 'FirstName', + lastName: 'LastName', + email: 'eMail', + password: 'Password' + }, + user : { + firstName: 'Andrew', + lastName: 'Joslin', + email: 'AndrewJoslin@drifty.com', + password: 'public' + } + } + }); + + it('should set input type `password` properly', function() { + var el = setupTextFloat( { type:"password" }, model); + expect( el.find('input').attr('type')).toBe("password"); + expect( el.find('input').val()).toBe(""); + }); + it('should set input type `email` properly', function() { + var el = setupTextFloat( { type:"email" }, model); + expect( el.find('input').attr('type')).toBe("email"); + expect( el.find('input').val()).toBe(""); + }); + + it('should set a static label properly', function() { + var el = setupTextFloat( { label:"motto" }, model); + expect( el.find('label').text() ).toBe("motto"); + + expect( el.find('input').attr('type')).toBe("text"); + expect( el.find('input').val()).toBe(""); + }); + it('should update a label from model changes.', function() { + var markup ='' + + ''; + var el = buildElement( markup, model); + + expect( el.find('input').val() ).toBe("Andrew"); + expect( el.find('label').text() ).toBe("FirstName"); + + // Change model value of the `firstName` [field] label + // then check if the dom is updated + + var val2 = "Corporate Title:"; + el.find('label').scope().$apply(function(){ + model.labels.firstName = val2; + }); + expect( el.find('label').text() ).toBe( val2 ); + + }); + it('should update an input value from model changes.', function() { + var markup ='' + + ''; + var el = buildElement( markup, model); + var input = el.find('input'); + + expect( input.val() ).toBe("Andrew"); + + var name = "AngularJS"; + input.scope().$apply(function(){ + model.user.firstName = name; + }); + expect( input.val() ).toBe( name ); + + }); + it('should update a model value from input changes.', function() { + var markup ='' + + ''; + var el = buildElement( markup, model); + var input = el.find('input'); + + expect( input.val() ).toBe( model.user.firstName ); + + input.val( "AngularJS" ); + input.triggerHandler('input'); + expect( model.user.firstName ).toBe( "AngularJS" ); + + }); + + it('should set input class for focus & blur', function() { + var expressions = {label:"Firstname", model:"user.firstName"}, + el = setupTextFloat( expressions, model), + input = el.find('input'); + + input.triggerHandler('focus'); + expect(el.hasClass('md-input-focused')).toBe(true); + input.triggerHandler('blur'); + expect(el.hasClass('md-input-focused')).toBe(false); + }); + it('should set input class for input event', function() { + var expressions = {label:"password", model:"user.password", type:"password"}, + el = setupTextFloat( expressions, model), + input = el.find('input'); + + expect(el.hasClass('md-input-has-value')).toBe(true); + + input.val(''); + input.triggerHandler('input'); + expect(el.hasClass('md-input-has-value')).toBe(false); + + input.val('ThomasBurleson@gmail.com'); + input.triggerHandler('input'); + expect(el.hasClass('md-input-has-value')).toBe(true); + }); + + it('should set input class for ngModel changes', function() { + var expressions = {label:"Password", model:"user.password", type:"password"}, + el = setupTextFloat( expressions, model), + input = el.find('input'); + + expect(el.hasClass('md-input-has-value')).toBe(true); + + input.scope().$apply(function(){ model.user.password = ""; }); + expect(el.hasClass('md-input-has-value')).toBe(false); + + input.scope().$apply(function() { model.user.password = "hiddenValley"; }); + expect(el.hasClass('md-input-has-value')).toBe(true); + }); + + }); + + // **************************************************************** + // Utility `setup` methods + // **************************************************************** + + var templates = { + md_text_float : '' + + '', + + md_input_group: '
' + + ' ' + + ' ' + + '
' + }; + + /** + * Build a text float group using the `` markup template + */ + function setupInputGroup(expressions, values) { + values = angular.extend({},{type:"text", id:''},values||{}); + + return buildElement( templates.md_input_group, values, angular.extend({}, expressions||{})); + } + + /** + * Build a text float group using the `` markup template + */ + function setupTextFloat(expressions, values) { + values = angular.extend({ modelValue:"",type:'text' }, values || {}); + + var defaults = {model:"modelValue", label:""}; + var tokens = angular.extend({}, defaults, expressions||{} ); + + return buildElement( templates.md_text_float, values, tokens ); + } + + /** + * Use the specified template markup, $compile to the DOM build + * and link both the bindings and attribute assignments. + * @returns {*} DOM Element + */ + function buildElement( template, scope, interpolationScope ) { var el; - inject(function($compile, $rootScope) { - el = $compile('
' + - '' + - '' + - '
')($rootScope.$new()); + + inject(function($compile, $interpolate, $rootScope) { + scope = angular.extend( $rootScope.$new(), scope || {}); + + // First substitute interpolation values into the template... if any + if ( interpolationScope ) { + template = $interpolate( template )( interpolationScope ); + } + + // Compile the template using the scope model(s) + el = $compile( template )( scope ); $rootScope.$apply(); + }); return el; } - it('should set input class for focus & blur', function() { - var el = setup(); - var input = el.find('input'); - input.triggerHandler('focus'); - expect(el.hasClass('md-input-focused')).toBe(true); - input.triggerHandler('blur'); - expect(el.hasClass('md-input-focused')).toBe(false); - }); - it('should set input class for input event', function() { - var el = setup(); - var input = el.find('input'); - input.val('cat'); - input.triggerHandler('input'); - expect(el.hasClass('md-input-has-value')).toBe(true); - input.val(''); - input.triggerHandler('input'); - expect(el.hasClass('md-input-has-value')).toBe(false); - }); - - it('should set input class for ngModel render', function() { - var el = setup('ng-model="something"'); - var input = el.find('input'); - expect(el.hasClass('md-input-has-value')).toBe(false); - input.scope().$apply('something = "123"'); - expect(el.hasClass('md-input-has-value')).toBe(true); - input.scope().$apply('something = ""'); - expect(el.hasClass('md-input-has-value')).toBe(false); - }); }); + +