Is it possible mask input using a different placeholder? - angularjs

Since my form has no labels, I would like to be able to use a different placeholder with Angular and Angular-UI-Utils-Mask:
<div ng-controller="myController">
<input type="text"
ng-model="date"
ui-mask="99/99/9999"
placeholder="Birth Date"/>
</div>
Using jquery-inputmask it works like a charm, but I had too many problems to make it work with Angular so I'm now trying to go Angular way, but Angular shows my input as:
Bi/th/Date
Here's a fiddle to show it: http://jsfiddle.net/XS4R6/
I also saw some people talking about ´ui-mask-placeholder´, but it does nothing.
Is there a way to accomplish this?
EDIT
To clarify, I think it's just fine to use just placeholders since you also use titles (hint) so people always know what are they supposed to type in those inputs:
The input showing __.___.___ is the one I'm using Angular UI Mask.
JQuery Inputmask works very fine, since it shows the 'name' placeholder and as soon as I mouse over or click the input it shows the mask.

I'm thinking you can use another tag to simulate placeholder, maybe the code here is not very good, but I just provide another thought.
app.directive("myPlaceholder", ['$compile', function($compile){
return {
restrict: 'A',
link: function(scope, elem, attr) {
attr.$observe('myPlaceholder', initialize);
var mask = '__/__/____';
function initialize(value) {
// label is not clickable in IE, that's the reason why we use span tag
var fakePlaceholder = angular.element('<span class="placeholder">' + value + '</span>');
// click placeholder to focus the input
fakePlaceholder.on('click', function(){
elem.focus();
});
elem.before(fakePlaceholder);
$compile(fakePlaceholder)(scope);
elem.on('focus', function() {
fakePlaceholder.hide();
}).on('blur', function() {
if (elem.val() === mask) {
fakePlaceholder.show();
}
});
}
}
};
}]);
demo on http://jsfiddle.net/XS4R6/19/ (jQuery required)

Related

Emoticons support for textarea or contenteditable div

Trying to implement a textarea component with emoticons support while writing.
I want to be able to backup the original text (ascii chars only) while presenting the filtered/generated html outcome (with an angular emoticons filter) on a div.
My initial solution is to
<textarea ng-model="text" ng-change="..." ng-focus="..."></textarea>
<div ng-bind-html="text | myEmoticonsFilter"></div>
but I'm having trouble getting to the part of using a hidden textarea. Also, with this I wouldn't be able to mouse-select text and delete or copy/paste safely.
I also thought of using a <div contenteditable="true"> but ng-focus and ng-change wouldn't be handled.
Does anyone have any sugestion on how to continue this?
Edit 1: here is a jsfiddle with an attempt on what I'm doing. Up until now, able to replace the first occurrence, but the behavior remains erratic since that. I'm using a contenteditable directive for 2-way data binding and to filter the emoticon pattern.
Edit 2: regarding my statement saying that ng-focus and ng-change wouldn't be handled, that is not true - ng-focus works natively on <div contenteditable="true"> and ng-change will work as long as a directive is declared using the ngModel and setting the appropriate $modelValue and $viewValue (an example is provided in the jsfiddle in Edit 1).
The only way to do this in a consistently cross-browser manner is to use a WYSIWYG field that converts emoji to images.
There's a jQuery plugin jquery-emojiarea that does what you need, so you'd just need to create a directive that wraps this plugin and you're off to the races. Since it inputs into a hidden textarea with emoji syntax :smile: angular should have no difficulty binding.
Here's a working directive I threw together. http://jsfiddle.net/dboskovic/g8x8xs2t/
var app = angular.module('app', []);
app.controller('BaseController', function ($scope) {
$scope.text = 'This is pretty awesome. :smile: :laughing:';
});
app.directive('emojiInput', function ($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function ($scope, $el, $attr, ngModel) {
$.emojiarea.path = 'https://s3-us-west-1.amazonaws.com/dboskovic/jquery-emojiarea-master/packs/basic';
$.emojiarea.icons = {
':smile:': 'smile.png',
':angry:': 'angry.png',
':flushed:': 'flushed.png',
':neckbeard:': 'neckbeard.png',
':laughing:': 'laughing.png'
};
var options = $scope.$eval($attr.emojiInput);
var $wysiwyg = $($el[0]).emojiarea(options);
$wysiwyg.on('change', function () {
ngModel.$setViewValue($wysiwyg.val());
$scope.$apply();
});
ngModel.$formatters.push(function (data) {
// emojiarea doesn't have a proper destroy :( so we have to remove and rebuild
$wysiwyg.siblings('.emoji-wysiwyg-editor, .emoji-button').remove();
$timeout(function () {
$wysiwyg.emojiarea(options);
}, 0);
return data;
});
}
};
});
And usage:
<textarea ng-model="text" emoji-input="{buttonLabel:'Insert Emoji',wysiwyg:true}"></textarea>
If you want the editable field to convert text like :( as you type you'll need to fork that jquery plugin and modify it slightly to parse input text on change as well as on init. (like, a couple lines of code)

AngularJS directive remove class in parent element

I am using the following code to add / remove class "checked" to the radio input parent. It works perfectly when I use JQuery selector inside the directive but fails when I try to use the directive element, can someone please check my code and tell me why it is not working with element and how I can possibly add/ remove class checked to the radio input parent while using element instead of the jquery selectors? Thanks
.directive('disInpDir', function() {
return {
restrict: 'A',
scope: {
inpflag: '='
},
link: function(scope, element, attrs) {
element.bind('click', function(){
//This code will not work
if(element.parent().hasClass("checked")){
scope.$apply(function(){
element.parent().removeClass("checked");
element.parent().addClass("checked");
});
}else{
scope.$apply(function(){
element.parent().addClass("checked");
});
}
//This code works perfectly
$('input:not(:checked)').parent().removeClass("checked");
$('input:checked').parent().addClass("checked");
});
}
};
});
HTML:
<div class="inpwrap" for="image1">
<input type="radio" id="image1" name="radio1" value="" inpflag="imageLoaded" dis-inp-dir/>
</div>
<div class="inpwrap" for="image2">
<input type="radio" id="image2" name="radio1" value="" inpflag="imageLoaded" dis-inp-dir/>
</div>
Your code actually works for me in Plnkr (more or less):
http://plnkr.co/edit/vJJRYQQxH7u2bKSc27UA?p=preview
When you run this, the 'checked' class gets correctly added to the parent DIVs using only the first code you included. (I commented out the jQuery mechanism - I didn't add jQuery to this page, as a test.)
However, I think what you're trying to accomplish isn't working out because you're only capturing click events. The radio button that loses its checked attribute doesn't get a click event, only the next one does. In jQuery your selector is really broad - you're hitting every radio button, so it does what you want. But since you only trap click on the radio button that receives the click, it doesn't do what you want using the other pattern. checked gets added, but never removed.
A more Angular-ish pattern would be something like this:
http://plnkr.co/edit/HN7tLxkRA0jUL5GPjk5V?p=preview
link: function($scope) {
$scope.checked = false;
$scope.$watch('currentValue', function() {
$scope.checked = ($scope.currentValue === $scope.imgNumber);
});
$scope.setValue = function() {
$scope.currentValue = $scope.imgNumber;
};
}
What you see here lets Angular do all the dirty work, which is kind of the point. You can actually go a lot further than this - you could probably cut half the code out and do it all with expressions. The point is that in Angular, you really want to focus on the DATA (the model). You wire all of your behaviors and events up (controller) to things that manipulate that data, and then wire up all your DOM styles, classes, templates (view), etc. up to conditionals against that same data. And that is the point of MVC!

autofocus doesn't work when used with ng-include

I want to set focus to one of the input box in partial view
like .
and including this by
This is working fine when page loads for the first time. but when I change the partials autofocus doesn't work .
I believe it is because of autofocus work on pageload how can it make work here
I am not sure how to fix the problem of page reload but I think we can work out another solution here. I wrote a small directive once to conditionally set focus on an input element.
Here is the code:
function SetFocusDirective($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.setFocus);
scope.$watch(model, function (value) {
if (value === true) {
element[0].focus();
}
});
element.bind('blur', function () {
scope.$apply(model.assign(scope, false));
});
}
};
}
SetFocusDirective.$inject = ['$parse'];
app.directive('setFocus', SetFocusDirective);
And here is how you can use it:
<input type="text" ng-model="firstName" set-focus="autofocusFirstName">
Where autofocusFirstName is a $scope variable which should have a boolean value.
So every time your partials load, all the directives inside them will get linked and do their jobs. If you end up using this directive, you should be able to achieve what you want.

Combining Polymer elements and angular

I have looked at a number of answers for binding Angular-JS scope data to Polymer components. (Use Angular-Bind-Polymer Another, And a third). It seems like this shouldn't be this hard, if the polymer components are truly just DOM. (Note that I'm using Chrome beta (36)).
I tried the Angular-Bind-Polymer suggestion, but no luck. My real interest is extending ngModel to work with Polymer so that I can use the Polymer check boxes, radio buttons, etc. For example, I tried getting paper-checkbox to work, so I tried the following, thinking that it should work:
var ngPaper = angular.module('ng-paper', []);
ngPaper.directive('paper-checkbox', function() {
console.log("Processing directive");
return {
restrict: 'E',
require: '?ngModel',
link: function(scope, element, attr, ctrl) {
console.log("Running linker");
element.on('click', function() {
scope.$apply(function() {
ctrl.$setViewValue(element[0].checked);
});
});
ctrl.$render = function() {
element[0].checked = ctrl.$viewValue;
};
ctrl.$isEmpty = function(value) {
return value != true;
};
ctrl.$formatters.push(function(value) {
return value === true;
});
ctrl.$parsers.push(function(value) {
return value ? true : false;
});
}
};
});
But no.
I then tried using angular-bind-polymer to bind the checked value on the paper-checkbox to a model attribute but didn't have any success.
I feel like if I could figure out how to get one of the form control elements to work, the others should fall quickly in line. Does anyone have a better idea on how to do this or an explanation as to why the directive I wrote isn't getting picked up and applied to the paper-checkbox?
I made this generic work-around that I use to watch changes on check-boxes and most Polymer elements from AngularJS, it's really useful while you find a more proper way, I hope it helps you.
You can also use it to manipulate Polymer Elements (E.g. Toggle).
in your HTML:
<paper-radio-group selected="firstOption">
<paper-radio-button label="First Option" id="firstOption" ng-click="change()"></paper-radio-button>
<paper-radio-button label="Second Option" id="secondOption" ng-click="change()"></paper-radio-button>
</paper-radio-group>
In the corresponding AngularJS controller, requites $scope.
var firstOption= document.querySelector('paper-radio-button[id="firstOption"]');
var secondOption= document.querySelector('paper-radio-button[id="secondOption"]');
console.log(firstOption);
console.log(secondOption);
$scope.change = function()
{
console.log(firstOption);
console.log(secondOption);
}
This way every time the user changes the selection, AngularJS will get notified so it can query the changes, you can scope the data you get back to something more specific, this is particularly useful to toggle Polymer Elements from AngularJS.
Let me know if this works for you, happy coding!

AngularJS and AngularUI: mask or format a phone number when binding

I am using AngularUI to format or "masking" a phone number input, and it works fine with a ng-model:
<input ng-model="emer.phone" ui-mask="{{'(999) 999-9999'}}" type="text"/>
Question:
But now how can I apply the same mask in the same way using ng-bind, I have something like this:
<td>{{emer.phone}}</td>
My problem:
The ng-model and ng-bind are in two different files in different locations, therefor the use of "$viewValue" is not an option for me
Any idea?
some documentation about AngularUI mask: http://angular-ui.github.io/ui-utils/
Thanks!
You should use ui-mask="(999) 999-9999" instead of ui-mask="{{'(999) 999-9999'}}".
The latter tries to bind to a model with '(999) 999-9999' on it.
SO far I couldn't find a simple solution using AngularUI mask, so I had to create a filter. I follow this: Format telephone and credit card numbers in AngularJS
And here is the jsfiddle: http://jsfiddle.net/jorgecas99/S7aSj/
angular.module('ng').filter('tel', function () {
return function (tel) {
if (!tel) { return ''; }
var value = tel.toString().trim().replace(/^\+/, '');
...
Cheers!
Instead of making your own masking or perhaps building your own directive you can make use of existing solutions.
Take tel.js for example. It is an input[tel] directive that formats and validates international phone numbers for you.
You can install it from bower like this:
bower install teljs --save
Then:
Link the two script files found in the 'src' folder: tel.js and metadatalite.js.
<script src="bower_components/teljs/src/tel.js"></script>
<script src="bower_components/teljs/src/metadatalite.js"></script>
Load the tel.js module.
angular.module('<your module>', ['teljs']);
You can try out tel.js here:
http://michaelkrog.github.io/tel.js/
Remark: I am the developer of tel.js.
I can see in the ui-mask demo, they cheat a bit and use the $viewValue from ngModelController.
So, you could try the same thing.
First, you must add a name to your input field and be wrapped in a form (with a name):
<form name="demo">
<input name="emerPhone" ng-model="emer.phone" ui-mask="{{'(999) 999-9999'}}" type="text"/>
<td>{{demo.emerPhone.$viewValue}}</td>
</form>
As you can see from the above example, the display code becomes:
<td>{{demo.emerPhone.$viewValue}}</td>
It would have been better if they would have provided a filter as well, though.
Also, I can see that in the demo for ui-mask, they show and hide based on the length of the $viewValue:
<div ng-show="demo.masked.$viewValue.length">NgModelController.$viewValue: <code>{{ demo.masked.$viewValue
}}</code></div>
<div ng-hide="demo.masked.$viewValue.length">NgModelController.$viewValue: <code>undefined</code></div>
Hope this helps.
Find Plunker for Formatting Credit Card Numbers using angularjs directive. Format Card Numbers in xxxxxxxxxxxx3456 Fromat.
angular.module('myApp', [])
.directive('maskInput', function() {
return {
require: "ngModel",
restrict: "AE",
scope: {
ngModel: '=',
},
link: function(scope, elem, attrs) {
var orig = scope.ngModel;
var edited = orig;
scope.ngModel = edited.slice(4).replace(/\d/g, 'x') + edited.slice(-4);
elem.bind("blur", function() {
var temp;
orig = elem.val();
temp = elem.val();
elem.val(temp.slice(4).replace(/\d/g, 'x') + temp.slice(-4));
});
elem.bind("focus", function() {
elem.val(orig);
});
}
};
})
.controller('myCtrl', ['$scope', '$interval', function($scope, $interval) {
$scope.creditCardNumber = "1234567890123456";
}]);

Resources