Retrieve data for an autocomplete form input with angular - angularjs

I have a form made with angular, one of the inputs is autocompleted with google maps. The problem is that if I write "Mad" and the autocomplete fills it with "Madrid" when the form is sent there is only "Mad" instead of "Madrid" and the same for longer addresses.
I had a similar problem autofilling the latitude and longitude obtained with the place of the autocomplete, but I solved it. I tried the same with the autocomplete input and is not working.
This is part of my form:
<fieldset class="form-group">
<input ng-model="newCtrl.event.formatted_addres" type="text"
ID="location-placheholder" class="form-control"
placeholder="Where will be the event?"
title="Location" required />
</fieldset>
<fieldset ng-show ="false" class="form-group">
<input ng-model="newCtrl.event.longitude" type="float"
ID="location-longitude" class="form-control"
title="Location-longitude" required />
</fieldset>
<fieldset ng-show ="false" class="form-group">
<input ng-model="newCtrl.event.latitude" type="float"
ID="location-latitude" class="form-control"
title="Location-latitude" required />
</fieldset>
and this is the autocomplete function for the formatted_address field:
function setupAutocomplete(){
var input = $('#location-placheholder')[0];
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.addListener('place_changed', function(){
var place = autocomplete.getPlace();
var infowindow = new google.maps.InfoWindow({
});
if (place.geometry.location) {
$("#location-longitude").val(place.geometry.location.lng().toFixed(7));
$("#location-longitude").trigger('input');
$("#location-latitude").val(place.geometry.location.lat().toFixed(7));
$("#location-latitude").trigger('input');
$("location-placeholder").val(place.formatted_address);
$("location-placeholder").trigger('input');
map.setCenter(place.geometry.location);
createMarker(place.geometry.location, place.formatted_address);
} else {
alert("The place has no location...?")
};
});
};
When I do
$("#location-latitude").val(place.geometry.location.lat().toFixed(7));
$("#location-latitude").trigger('input');
The input of latitude fills correctly and is sent correctly, but if I do:
$("location-placeholder").val(place.formatted_address);
$("location-placeholder").trigger('input');
It keeps sending only the part of the address that I have already written, not the rest of the address filled with the autocomplete.
Thanks
I add a fiddle with my code, I've been trying to make it work without the $http requests, but I couldn't. So I hope this is enough to evaluate my code.
http://jsfiddle.net/sjc7jtbp/1

Finally I solved it, for some reason ajax was not targeting the input. So I created a new input hidden with ng-show="false" and I labelled it as class="autofill".
So later I aimed at it as $('.autofill') and it worked. The rest is submit this input and not the original one. Maybe it is not an elegant solution, but it works.

Related

angular submitting only form data not whole model

I'm submitting form data to my API but my model contains my whole object. I should really only submit the updates, correct?
So,
my item is retrieved by Id, which I don't need to show to the user (hidden field).
I'll show the user the title of item so they know what they're editing, but I won't make it editable (read-only).
I'll expose description so the user can edit it and save.
(Imagine a larger form - a half dozen more read-only fields and a half dozen more editable fields.)
Correct me if I'm wrong but, when sending to my API, I should not be sending the entire item object. The db already has title, why put it in the payload if its just going to be thrown away?
So, I should really only be sending the values of the editable fields.
I'm trying to figure out the proper way of separating the model from the form data so I submit the latter, not the former. If this is not best practice, please correct me.
Controller:
.controller('editItemController', ['$stateParams',
function($stateParams) {
var vm = this;
vm.getItem = function () {
$http.get('/api/Items/' + $stateParams.id).then(function (response) {
vm.item = response.data;
});
};
vm.saveChanges = function () {
vm.submitted = true;
if (vm.detailsForm.$valid) {
$http.put('/api/Items/' + $stateParams.id, vm.item).then(function (response) {
});
}
};
vm.getItem();
}
View:
<form name="itemVm.detailsForm" ng-controllerAs="itemVm">
<input type="hidden" name="Id" ng-model="itemVm.item.Id" />
<div class="form-group">
<label for="title" class="control-label col-xs-3">Title:</label>
<div class="col-xs-9">
<input type="text" class="form-control" readonly="readonly" id="title" value="{{ itemVm.item.Title }}">
</div>
</div>
<div class="form-group">
<label for="description" class="control-label col-xs-3">Description:</label>
<div class="col-xs-9">
<input type="text" class="form-control" name="description" ng-model="itemVm.item.Description" required>
</div>
</div>
<button ng-click="itemVm.saveChanges()">Save Changes</button>
</form>
For a standard REST API, you should be sending the entire object. The entire idea behind REST is that you transfer representations of the state of an object, hence representational state transfer. As such, it should be a complete representation, not a portion.
There are multiple ways to circumvent this if you'd really like, and most have to do with the back end, not the front end.
Either create an ad hoc endpoint to take in the one parameter and update the persistent object accordingly. (Not recommended).
If you want to send partial data (which I think is a good idea some times depending on the size of the object), you should handle that on the back end accordingly.
See here.

Getting Text from Modal : Protractor / Webdriver

<input type="text" class="form-control input-lg" id="name" placeholder="Insert Your Name Here" ng-model="form.Name" required>
I have a model called as above. I'm trying to validate the text after it's inputted. I've seen other similar examples but nothing is working for me. I'm trying to test it with this setup. I end up getting
Expected null to equal 'Your Inputted Text'
In Page Object File.
this.formInput = element(by.model('form.Name'));
In Testing File.
setup.formInput.sendKeys('Jim');
setup.formName.click().then(function () {
expect(setup.formInput.getAttribute('form.Name')).toEqual('Jim');
});
How can I capture / confirm the text that was entered?
setup.formInput.getAttribute('value')
Not tested. But I am hoping that will return you the text you want

Have AngularJs update {{binding}} as the user types in input[email]

Angular only updates the model from an input[email] after the user has entered a valid email address. How can I add a {{binding}} somewhere on the page that will update with the email value as the user types -- even before the user has typed in a valid email address?
Here's what I've tried so far:
<div ng-app>
<div ng-controller="MyCtrl">
<form name="MyForm" novalidate>
Name: <input type="text" name="name" ng-model="contact.name" /><br/>
Name as you type: {{contact.name}}<br/>
Email: <input type="email" name="email" ng-model="contact.email" /><br/>
Email as you type: {{contact.email}} (doesn't work)<br/>
Also doesn't work: {{$document.forms.MyForm.elements.email.value}}
</form>
</div>
</div>
Controller:
function MyCtrl($scope) {
$scope.contact = {};
}
(fiddle)
The name updates in real-time like I want, but the email doesn't.
I'd like to leave the email validation enabled. I just need some way to bind the un-validated input[email] text, so it updates as the user types.
Update 2014/7/8
I'd like to add an explicit requirement that the type="email" remains unchanged. I do not want to change the semantics of the markup to workaround a limitation of the framework. If need be, I'd rather pull in a complementary dependency (such as jQuery) to shim in the needed functionality.
I'm not opposed to handling validation in the controller — as suggested by rageandqq and charlietfl — if it could be done easily. Looking around though, it looks like it could be tricky (given my requirements).
That is how angularjs works. If you use <input type="email" /> angular is not going to bind your input till input will be valid in this case value must be a proper e-mail address.
please read more here : https://github.com/angular/angular.js/issues/1426
The workaround I've come up with so far is to use jQuery to listen for the input change and update an object on $scope that I've called formRaw. It works. Still, I'm hoping someone will come along and show me a better way.
The updated example:
<div ng-app>
<div ng-controller="MyCtrl">
<form name="MyForm" novalidate>
Name: <input type="text" name="name" ng-model="contact.name" /><br/>
Name as you type: {{contact.name}}<br/>
Email: <input type="email" name="email" ng-model="contact.email" /><br/>
Email Model: {{contact.email}}<br/>
Email Form: {{formRaw.email}}
{{q}}
</form>
</div>
</div>
And controller:
function MyCtrl($scope) {
$scope.contact = {};
$scope.formRaw = {};
$('input[type=email]').on('keyup change', function () {
var input = $(this);
$scope.formRaw[input.attr('name')] = input.val();
$scope.$digest(); // FIXME: there's got to be a better way
});
}
(fiddle)
The type="email" attribute on your E-mail input is what is causing the DOM binding to mess up.
Changing it to type="text" works allows your {{contact.email}} to display correctly.
Edited JSFiddle.

How to use Angular input fields email validation inside controller?

I'm trying to validate a variable as email inside Angular controller.
var valid = $filter('email')($scope.email);
The email filter doesn't exists, generates "unknown provider error". What's the correct way to access email validation from inside the controller?
Thanks.
Later edit: don't put me to create a custom filter, it must be a way using angular validation.
You can create a hidden input type email:
<input type="email" hidden id="emailValidator" required ng-model="x" />
Then in js set the value to that input and check validity:
var validator = $('#emailValidator')[0];
validator.value = "someemail#tovalidate.com";
return validator.checkValidity();
Also this documentation could be helpful: https://docs.angularjs.org/guide/forms
You could use form and prevent form submission by adding ng-disabled to the submit button:
<form name="form">
<input type="email" ng-model="email" name="email" required/>
<button type="submit"
ng-disabled="form.$invalid">Submit</button>
</form>
{{form.email.$valid}}
As the point of validation is to prevent submission and show error messages. I think it's enough to do it there instead of controllers where you handle your business logic.
DEMO
You can write your own filter:
angular.module(/**some module description here**/).
filter('email',function(){
var validateEmail = function(email) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
return function(input){
return validateEmail(input);
};
});
Regular expression is borrowed from here

Get "raw" value from invalid input field

I have an input field in a form with some validations. It works like a charm.
It basically looks like this:
<input
class="form-control"
type="number"
ng-model="zipcode"
ng-minlength="5"
ng-maxlength="5"
id="zipcode"
name="zipcode"
required
>
A working plunkr is here: http://plnkr.co/edit/H0h59kG75T5MGE9cAhSo?p=preview
But now I also want to react to every input change - whether valid or not. So for example if the input field contains "123" it is not valid and the value is not transferred to my model - thats fine. But I still want to get the value to do some intermediate requests to a webservice.
Any Ideas?
First call the form element in your controller, then use the $viewValue attribute :
View :
<form name="form">
<input
...
ng-model="zipcode"
ng-change="getRawValue(form)"
name="zipcode"
required
>
</form>
Controller:
$scope.getRawValue = function(form) {
var rawValue = form.zipcode.$viewValue;
}
Angular 1.3 introduced a real answer for this: allowInvalid in ngModelOptions.
Example:
<input
type="text"
name="userName"
ng-model="user.name"
ng-model-options="{allowInvalid: true}"
>
Here is what i came up with for your scenario.
Basically you can write a directive which requires ngModel (ngModelController). The ngModelController has a array of parsers which it call to parse the view value in a pipeline manner. If validation fail these parsers do not update the model. If you inject a custom parser at the start of this parsers array, you can get the each view change value and do anything you want with it.
See my plunkr here http://plnkr.co/edit/ruB42xHWj7dBxe885OGy?p=preview (See console)
The basic code would be
ngModelCtrl.$parsers.splice(0,0,(function (viewValue) {
console.log("The view value is:"+viewValue)
return viewValue;
}));
Also see ngModelController documenation

Resources