Just wondering why the ngblur directive did not get the complete value of a text input. I am using easyautocomplete plugin to do search through a JSON file.
When it found it will list out several suggestions that could be match to the input. The problem is when we do not type the full text and choose to select from the provided list, ngblur will only capture what we have typed to the input box instead of what we choose from the list.
Here is the fiddle https://jsfiddle.net/zvezrg6j/
json country is Indonesia or Singapore or Thailand
UPDATE
What i wanted to do is when i choose from the list or when i leave the text input with full text, the app will look up for some details, eg. after typing the country the app will look for its capital.
This is the solution you are looking for.
Updated JSFiddle
Instead of calling FindMaterialDetail method on blur, call it onHideListEvent of auto-complete options.
angular.module('myapp', [])
.controller('MyCtrl', function($scope) {
$scope.data = {};
$scope.FindMaterialDetail = function(country) {
var scope = angular.element($("#outer")).scope();
scope.$apply(function(){
scope.data.result = country;
})
}
var options = {
url: "https://api.myjson.com/bins/1rjn5",
getValue: "country",
listLocation: "data",
list: {
match: {
enabled: true
},
onHideListEvent: function() {
$scope.FindMaterialDetail($("#Autocomplete").val());
}
}
};
$("#Autocomplete").easyAutocomplete(options);
});
The option you can try is using $scope.$watch for the model. Instead of calling the function in ngblur try adding the following snippet in your script.
$scope.$watch("data.country", function(event) {
$scope.data.result = $scope.data.country;
});
Please find the modified fiddle.
This issue is occurring because blur event is firing before value update in 'data.country', You can resolve this issue by using below code. Create A directive like below-
angular.module('app', []).directive('easyAutoComplete', function() {
return {
restrict: 'A',
require: 'ngModel',
priority: 1, // needed for angular 1.2.x
link: function(scope, elm, attr, ngModelCtrl) {
var options = {
url: "https://api.myjson.com/bins/1rjn5",
getValue: "country",
listLocation: "data",
list: {
match: {
enabled: true
},
onChooseEvent: function() {
scope.$apply(function() {
ngModelCtrl.$setViewValue($(elm).getSelectedItemData().country);
});
}
},
};
$(elm).easyAutocomplete(options);
}
};
});
then use it like as -
<input type="text" ng-model="data.country" easy-auto-complete ng-change="FindMaterialDetail(data.country)" id="Autocomplete">
There is a problem on loading jquery autocomplete Plugin in your angular code , as the angular code got initialized first followed by the autocomplete .
So i've converted the above code to Angular Bootstrap Typehead which is exactly does the autocomplete written in angular way .It's also recommended to use angular directives rather than jquery plugins for building angular applications
Check for Custom templates for results on this link.
Angular Autocomplete TypeAhead
Here is the Fiddle
<input type="text" ng-model="data.country" placeholder="Custom template" uib-typeahead="country as country for country in Countries" typeahead-show-hint="true" typeahead-min-length="0" ng-blur="FindMaterialDetail(data.country)" class="form-control">
Related
I am using angular ui-select for autocomplete. When the user start typing, I want to show the best matching item as watermarked, and when the user press tab, it should be selected (same like google auto suggest)
Please see the image also. you can see that, when I type 'auto' 'complete' is shown as watermark and if I pres TAB, it will be selected.
there are a bower plugin autocompletelikegoogle and you can create an angular directive to render an autocomplete input in your application.
Directive.js
angular.module('app').directive('autoComplete', [
'$timeout', function($timeout) {
return function(scope, element, attrs) {
var auto;
auto = function() {
$timeout((function() {
if (!scope[attrs.uiItems]) {
auto();
} else {
element.autocomplete({
source: [scope[attrs.uiItems]]
});
}
}), 5);
};
return auto();
};
}
]);
HTML use example
<input type="text" auto-complete ui-items="list" ng-model="yourModel" class="form-control" placeholder="Tipe something" />
The variable list contains an array of your possible results in autocomplete input, is set in the atribute called ui-items.
Use angular-ui select library...It will make REST call to get data from backend systems for autocomplete dropdown....and for watermark..You can change it through CSS.
for library please find URL:https://github.com/angular-ui/ui-select
I'm using AngularJS/Firebase (AngularFire) & Google Maps API to create a basic travel wishlist.
So far I have the following:
HTML:
<form ng-submit="setNewEntry(field)">
<input type="text" googleplace ng-model="field" />
</form>
Controller function:
$scope.setNewEntry = function(val) {
ref.child("places").push({
"location": val
})
$scope.field = "";
}
Directive: (to bind autocomplete to input)
.directive('googleplace', function() {
return {
link: function(scope, element, attr) {
scope.gPlace = new google.maps.places.Autocomplete(element[0]);
}
}
})
This all works fine and pushes the value through to my Firebase app. The issue I'm having is with ng-model not picking up the value that Google provides.
Say I type 'nashville' and I get an autocomplete suggestion, I click on it and it fills in the input with 'Nashville, TN, United States' - once I hit enter to submit the form, it pushes through my initial search query 'nashville'.
Any ideas on how I would pass through the final value of the input?
Thanks!
I think you have not created a variable that whill hold the values of the autocomplete results . There is a simple directive for adding google places autocomplete to a textbox element which is called as ng-Autocomplete.
Please refer to the following code example to know more about the code implementation I am talking about.
//create new autocomplete
//reinitializes on every change of the options provided
var newAutocomplete = function() {
scope.gPlace = new google.maps.places.Autocomplete(element[0], opts);
google.maps.event.addListener(scope.gPlace, 'place_changed', function() {
scope.$apply(function() {
// if (scope.details) {
scope.details = scope.gPlace.getPlace();
// }
scope.ngAutocomplete = element.val();
});
})
}
newAutocomplete()
I want to implement a search box in my angularJs application. As soon as user starts typing some name in the search box , some REST service should be called and it should fetch all the names which matches the name typed in the search text box. Note that there is no button , the result should come automatically as soon as user starts typing. The REST service is already there. I just need to invoke the REST service when the user starts typing and return the result as a list.
For ex:- If I type James then all the user whose name starts with James should come as a list in the search box.
Once the list of name comes , the user can click on one of the name and his information should be loaded in the current page.
How can I implement such type-on search box in angular js? Is there any directive for it? Can anyone please give me some direction.
You should define a directive that listen onkeypress.
app.directive('myOnKeyDownCall', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
});
};
});
HTML
<input type="text" my-on-key-down-call="callRestService()">
CONTROLLER
$scope.callRestService= function() {
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
$scope.results.push(data); //retrieve results and add to existing results
})
}
Would be nice to wait until 3 keys has been typed, for that in directive:
var numKeysPress=0;
element.bind("keydown keypress", function (event) {
numKeysPress++;
if(numKeysPress>=3){
scope.$apply(function (){
scope.$eval(attrs.myOnKeyDownCall);
});
event.preventDefault();
}
});
Perhaps, exists typeahead directive from angular-ui that you can use:
angular-ui typeahead
I hope it helps you
Found this to be a simplification of the accepted answer.
// Directive
app.directive('search', function () {
return function ($scope, element) {
element.bind("keyup", function (event) {
var val = element.val();
if(val.length > 2) {
$scope.search(val);
}
});
};
});
// In Controller
$scope.search= function(val) {
// fetch data
}
// HTML
<input type="text" search>
Not sure if you already solved this, but I recommend looking at this tutorial: http://angular.github.io/angular-phonecat/step-12/app/#/phones
Essentially it does what you're interested in, but instead it filters out the results while typing. If you got this working, I'm interested in how you did it. I'm trying this as well.
Why so much drama, directives, and Glyptodon blood?
Since angular already has
ng-keypress
ng-keyup
ng-keydown
Use any of those to invoke REST service just as you would with ng-click.
HTML
<input type="search" ng-model="vm.query" ng-keyup="vm.search()" />
JS
vm.search = search;
function search() {
// Call your cool REST service and attach data to it
vm.data = MyCoolService.myGetFunctionWhatever();
// You can use vm.query ng-model to limit search after 2 input values for example
// if(vm.query.length > 2) do your magic
};
Bootstrap's "Typeahead, Asynchronous results" does exactly what you want, easily. Go to https://angular-ui.github.io/bootstrap/ then scroll down near to the bottom of the page. I used it in my CRUDiest movies database project: https://crudiest-firebase.firebaseapp.com/#/movies
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";
}]);
I'm using angular js to handle the processing of data on my form. It uses ng-keyup to listen to changes to the input values, and display messages as a result.
To enter their date of birth, the user can either type directly into three text boxes or use a jquery plugin called pickaday, which allows the user to pick a date and then writes the date out to the three text boxes. Since I can add the ng-keyup attribute to the text boxes, processing of the date of birth is straightforward if the user types it rather than using the pickaday plugin.
The initialisation script of the pickaday plugin allows you to specify a callback function for whenever the user chooses a date. I need to somehow get this callback to run the code in my controller, so that the same code runs when the user picks a date from the plugin as if he had typed it in.
Is there a way I can do this?
NB: I tried simply using ng-change rather than ng-keyup for the three text boxes, hoping that ng-change would pick up on changes to the text boxes made by the pickaday plugin, but that didn't work. :(
The correct way to do this is a directive. Sounds like you would like two-way databinding working between angular and the jQuery plugin. I'm just guessing how the plugin works but I think you get the idea
app.directive('pickday', function() {
return {
scope: {
// note you can also pass a function
value: '='
},
// watch for changes on controller value
controller: function ($scope, $element) {
$scope.$watch('value', function(newVal, oldVal) {
angular.element($element).pickday({
value :parseInt($scope.value, 10)
});
});
},
// initialize pickday
link: function ($scope, $element, attr) {
$element.pickday({
value: parseInt($scope.value, 10),
//use the callback from pickday, note apply to trigger angular digest
change: function(event, ui) {
if (event.originalEvent) {
$scope.value = ui.value;
$scope.$apply();
}
}
});
},
template: '<div class="pickday"></div>'
};
});
Then use the directive on your view like this:
<pickday value="value.fromScope"></pickday>
Eventually, I got it working just fine like this:
.directive('datepicker', function() {
return {
link: function (scope) {
var minYear = moment().year() - 90,
maxYear = moment().year() - 13,
today = moment().subtract('years', 13);
var picker = new Pikaday({
field: document.getElementById('datepicker'),
trigger: document.getElementById('date-button'),
defaultDate: today.toDate(),
maxDate: today.toDate(),
yearRange: [minYear, maxYear],
onSelect: function() {
scope.$apply(function() {
scope.dayOfBirth.value = picker.getMoment().date();
scope.monthOfBirth.value = picker.getMoment().month() + 1;
scope.yearOfBirth.value = picker.getMoment().year();
scope.dateOfBirth.validate();
});
}
});
}
};
});
The directive can be triggered with the following HTML:
<div datepicker></div>