I am using ng-init to get some default values in my input fields. Its working properly. But when I add ng-autocomplete to the input field the default value is no longer showing in input field.
index.html
<!DOCTYPE html>
<html ng-app=testApp>
<head>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
<script src="script.js"></script>
<script src="ngAutocomplete.js"></script>
</head>
<body>
<div ng-controller="searchCtrl" ng-init="roomsInit('london')">
<input type="text" ng-autocomplete ng-model="searchLocation" class="form-control input-lg" options="locationFilter">
</div>
</body>
</html>
script.js
app = angular.module("testApp", ['ngAutocomplete']);
app.controller('searchCtrl', function ($scope, $http) {
$scope.locationFilter = {
country: 'uk',
types: '(cities)'
}; $scope.details2 = '';
$scope.roomsInit = function (location) {
$scope.searchLocation = location;
//below code is not relevant to this case
$http({
url: "/search.json",
method: "GET",
params: {location: $scope.searchLocation,
q: {
daily_price_gteq: $scope.min_price,
daily_price_lteq: $scope.max_price,
room_type_eq_any: [$scope.private, $scope.entire, $scope.shared]
}
},
paramSerializer: '$httpParamSerializerJQLike'
}).success(function (response) {
$scope.rooms = response.rooms;
});
};
});
If I remove the ng-autocomplete it works fine.Could someone have a look
Here is the plunker
The directive you are using doesn't support ng-model and requires you to pass your model to ng-autocomplete:
<input type="text" ng-autocomplete="result" details="details" class="form-control input-lg" options="locationFilter">
This runs the auto-complete when you type in the box.
I believe the directive you are after is this one: https://github.com/wpalahnuk/ngAutocomplete/blob/master/src/ngAutocomplete.js
UPDATE
The directive you are using has a watch which clears the value after it runs the first time:
scope.$watch(scope.watchOptions, function () {
initOpts()
newAutocomplete()
element[0].value = ''; // <-- This resets the value
scope.ngAutocomplete = element.val();
}, true);
If you don't care about modifying the directive, change it to this:
scope.$watch(scope.watchOptions, function (newValue, oldValue) {
if (newValue !== oldValue) {
initOpts()
newAutocomplete()
element[0].value = '';
scope.ngAutocomplete = element.val();
}
}, true);
This stops it from wiping out the value unless you change the options/locationFilter.
Related
I have a mysql database/node backend, connected to an Angular frontend, that I am querying, specifically to send it the data from 3 simple text inputs in a form.
I believe my error is quite trivial for anyone with node/angular experience because I can successfully send my database input from one of the text inputs; however, when I try to detect and send data from all three inputs, it only sends the data from whichever input has its matching controller function as the last one (of the three) in my script.
Here is my html file and the script
var button = document.getElementById("clickButton");
const app = angular.module('app',[]);
app.service('appService', ['$http', function($http){
return {
'getSuggestion' : function(suggestion,callback){
$http.post('/getSuggestion', {
'suggestion': suggestion
}).success(function (response) {
callback(response);
})
.error(function (data, status, header, config) {
callback({
'error': true,
'message': "Something went wrong."
});
});
}
}
}]);
app.controller('app', function($scope,appService) {
//message send Function
$scope.$watch('messageInput', function (newValue, oldValue) {
//null check
if (newValue !== null) {
//wait for the button to be pressed
button.onclick = function() {
alert("USERNAME");
//call server query function
appService.getSuggestion(newValue, function (response) {
$scope.suggestionCollection = response.rows;
});
};
}
});
$scope.$watch('messageInput2', function (newValue, oldValue) {
//null check
if (newValue !== null) {
//wait for the button to be pressed
button.onclick = function() {
alert("PASSWORD");
//call server query function
appService.getSuggestion(newValue, function (response) {
$scope.suggestionCollection = response.rows;
});
};
}
});
$scope.$watch('messageInput3', function (newValue, oldValue) {
//null check
if (newValue !== null) {
//wait for the button to be pressed
button.onclick = function() {
alert("PASSWORD");
//call server query function
appService.getSuggestion(newValue, function (response) {
$scope.suggestionCollection = response.rows;
});
};
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="app" ng-controller="app">
<head>
<title>Node app</title>
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div class="formFields">
<form class="defaultForm" id="loginForm">
<input class="loginField" type="text" name="username" ng-model="messageInput" placeholder="username"> <br>
<input class="loginField" type="text" name="password" ng-model="messageInput2" placeholder="password"> <br>
<input class="loginField" type="text" name="username" ng-model="messageInput3" placeholder="pass conf"> <br>
<button id="clickButton" class="submitButton">submit</button>
</form>
</div>
<!--<script src="Scripts/login.js"></script>-->
<script src="js/angular.min.js"></script>
<script src="js/script.js"></script>
</body>
</html>
You have a $watch for each input, and you have a submit() for each input. This is why you send only the input that changed. If you want to send them all together you should hold one submit(), means one onClick() that will check all new values are not null and send them to the server, something like this:
$scope.$watch('allInput', function (newValues, oldValues) {
//null check
if (newValues.user !== null && newValues.pass !== null && newValues.pass2 !== null) {
//wait for the button to be pressed
button.onclick = function() {
alert("USERNAME");
alert("PASSWORD");
alert("PASSWORD CONF");
//call server query function
appService.getSuggestion(newValues, function (response) {
$scope.suggestionCollection = response.rows;
});
};
}
});
and the html:
<form class="defaultForm" id="loginForm">
<input class="loginField" type="text" name="username" ng-model="allInput.name" placeholder="username"> <br>
<input class="loginField" type="text" name="password" ng-model="allInput.pass" placeholder="password"> <br>
<input class="loginField" type="text" name="username" ng-model="allInput.pass2" placeholder="pass conf"> <br>
<button id="clickButton" class="submitButton">submit</button>
</form>
Of course getSuggestion() will change as well:
app.service('appService', ['$http', function($http){
return {
'getSuggestion' : function(data,callback){
$http.post('/getSuggestion', {
'name': data.name,
'pass': data.pass,
'pass2': data.pass2
}).success(function (response) {
callback(response);
})
.error(function (data, status, header, config) {
callback({
'error': true,
'message': "Something went wrong."
});
});
}
}
If I understand your question correctly, you want to watch for changes of values in all three input fields. If user types anything in any one of the three input fields, you want to send the values from all three input fields to your backend. And when user hits "Submit", you want to get values from all three input fields as well.
To solve this problem, you need two pieces:
set up a persistent click event handler on the button, as opposed to adding one only when some change happens. Note that in your code, you are updating this click handler each time one of the three input fields changes. This would cause the new input handler to overwrite the old one. That's why you only get the last touched value. I would recommend looking into the ng-click directive.
get inputs from all three form fields when any one of them is changed. This can be achieved through the ng-change directive. Or alternatively, you can put all three ngModels under one parent object and just $watch() that one parent object, as Hatzav Wolff suggests in his answer.
Here is how I would approach it:
var button = document.getElementById("clickButton");
const app = angular.module('app',[]);
app.service('appService', ['$http', function($http){
return {
'getSuggestion' : function(suggestion,callback){
$http.post('/getSuggestion', {
'suggestion': suggestion
}).success(function (response) {
callback(response);
})
.error(function (data, status, header, config) {
callback({
'error': true,
'message': "Something went wrong."
});
});
}
}
}]);
app.controller('app', function($scope,appService) {
$scope.handleChange= function() {
/* Do whatever you want with the input. They are all here */
console.log($scope.messageInput + ' ' + $scope.messageInput2 + ' ' + $scope.messageInput3);
}
$scope.handleSubmit= function() {
/* Do whatever you want with the input. They are all here */
console.log($scope.messageInput + ' ' + $scope.messageInput2 + ' ' + $scope.messageInput3);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="app" ng-controller="app">
<head>
<title>Node app</title>
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div class="formFields">
<form class="defaultForm" id="loginForm">
<input class="loginField" type="text" name="username" ng-model="messageInput" ng-change="handleChange()" placeholder="username"> <br>
<input class="loginField" type="text" name="password" ng-model="messageInput2"ng-change="handleChange()" placeholder="password"> <br>
<input class="loginField" type="text" name="username" ng-model="messageInput3" ng-change="handleChange()" placeholder="pass conf"> <br>
<button id="clickButton" ng-click="handleSubmit()" class="submitButton">submit</button>
</form>
</div>
<!--<script src="Scripts/login.js"></script>-->
<script src="js/angular.min.js"></script>
<script src="js/script.js"></script>
</body>
</html>
I have 10 input fields each of them looks like:
<input type='text' ng-model='value1' ng-keyup='checkValue($event)'>
now inside my angular controller, the checkValue function is
$scope.checkValue = function(event){
if(event.target.value > someOtherDynamicValue){
// I have to reset the value here
event.target.value = "";
}
}
here the value is getting empty if the if condition is true but the problem is this value is not removing from ng-model. So I tried to access the ng-model name of the target element like this:
var modelName = angular.element(event.target)[0]attributes[2].nodeValue;
So now in modelName i have the ng-model name of the target element and I tried to reset it :
$scope.modelName = "";
So finally my code looks like:
$scope.checkValue = function(event){
if(event.target.value > someOtherDynamicValue){
// I have to reset the value here
event.target.value = "";
var modelName = angular.element(event.target)[0]attributes[2].nodeValue;
$scope.modelName = "";
}
}
I know it is treating $scope.modelName as a new independent scope variable but how can I change the value of ng-model?
EDIT
What I really want to achieve is: I have 10 fields with different ng-model name now when I am writing the angular function, I don't want to use the ng-model directly inside the function. Example:
$scope.checkValue = function(event){
if(event.target.value > someOtherDynamicValue){
// I have to reset the value here
$scope.value1 = ""; //I don't want to do this, because $scope.value1 is for one text field and I have 10 filed if i use this i need to write it 10 times
}
}
So $scope.value1 I want to generate dynamically using event.target.
Thanks.
Based on values you enter on third textbox values of one and two changes
// Code goes here
var app = angular.module('TestApp', []).controller('HomeController', HomeController);
HomeController.$inject = ['$scope'];
function HomeController($scope) {
var home = this;
home.checkValue = function($event) {
if ($event.target.value < 100) {
home.val1 = 0;
}else{
home.val2 = 10;
}
}
}
<!DOCTYPE html>
<html ng-app="TestApp">
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="HomeController as home">
<div>
{{ home.val1 }} | {{ home.val2 }} | {{ home.val3}}
</div>
<input type="number" ng-model="home.val1" ng-keyup='home.checkValue($event)'>
<input type="number" ng-model="home.val2" ng-keyup='home.checkValue($event)'>
<input type="number" ng-model="home.val3" ng-keyup='home.checkValue($event)'>
</div>
</body>
</html>
I am trying to submit form on ng-submit event but form submit is not working.
$http,$state,dtoResource are injections
where dtoResource is factory which modify json data.
My code is as below
index.html
<!DOCTYPE html>
<html ng-app="autoQuote">
<head lang="en">
<meta charset="UTF-8">
<title>Angular Js DTO mgnt</title>
<!-- Style sheets -->
<link href="css/bootstrap.css" rel="stylesheet"/>
<link href="css/app.css" rel="stylesheet"/>
<!-- Library Scripts -->
<script src="js/jquery.js"></script>
<script src="js/angular.js"></script>
<script src="js/angular-ui-router.js"></script>
<!-- Application Script -->
<script src="app/app.js"></script>
<!-- Services -->
<script src="common/services/common.services.js"></script>
<script src="common/services/dtoResource.js"></script>
<!-- Controllers -->
<script src="app/ctrl/autoQuoteCtrl.js"></script>
<script src="app/ctrl/questionsCtrl.js"></script>
</head>
<body>
<ul>
<li>step 1
<li>step 2
</ul>
<div class="container">
<div ui-view=""></div>
</div>
</body>
</html>
step1.html
Email:
autoQuoteCtrl.js
(function () {
"use strict";
angular
.module("autoQuote")
.controller("autoQuoteCtrl", ["$http","$state","dtoResource",autoQuoteCtrl]);
function autoQuoteCtrl($http,$state,dtoResource) {
console.log('We are in form');
//self = this;
// if valid (check form validate true)
//console.log(dtoResource);
//call function from your service, and do something with it
dtoResource.rc1Step1DTO();
$http({
method : 'POST',
url : 'api.php',
data : { dtoObj: JSON.stringify(prepareAutoQuoteDTO.postAutoQuoteObj) }, // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
})
.success(function(data) {
console.log(data);
if (!data.success) {
} else {
// if successful, bind success message to message
//$scope.message = data.message;
}
});
}
}());
dtoResource.js
(function () {
"use strict";
angular
.module("autoQuote")
.factory("dtoResource",
["$resource",
dtoResource]);
console.log('inside dtoResource');
function dtoResource(){
var prepareAutoQuoteDTO = {
postAutoQuoteObj : $.getAutoQuoteObject(),
initializeDriverObj: function(){
var driverLocObj = new Driver();
driverLocObj.PersonInfo = new PersonInfo();
driverLocObj.DriverLicense = new DriverLicense();
driverLocObj.Incident = new Incident();
return driverLocObj;
},
initializeAppInfo: function(){
var appInfoLocObj = new ApplicationInfo();
appInfoLocObj.Discount = new Discount();
return appInfoLocObj;
},
/*
* Initialize Vehicle object for autoQuoteDTO.js
*/
initializeVehicleObj: function(){
var vehicleLocObj = new Vehicle();
return vehicleLocObj;
},
/*
* store session info
*/
rc1Step1DTO: function(){
var emailId = $('#save_quote_email').val();
if (typeof emailId !== "undefined" && emailId && emailId != '' && emailId != 'Email Address'){
var email = new Email();
email.EmailTypeCd = 'PRIMARY';
email.EmailAddress = emailId;
this.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo = this.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo || new Contact();
this.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails = [];
this.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails.push(email);
}
}
};
return prepareAutoQuoteDTO;
}
}());
You have to add ng-app and ng-controller attributes to parent DOM elements.
And you can not invoke controller's instance in ng-submit :)
You should add special method in the controller, and call that one.
Something like this
<body ng-app>
<div ng-controller="autoQuoteCtrl">
<form ng-submit="onSubmit()">
...
</form>
</div>
</body>
And your controller something like this
angular
.module("autoQuote")
.controller("autoQuoteCtrl", ["$http","$state","dtoResource", function($http, $state, dtoResource) {
$scope.onSubmit = function() {
alert('hi, I was invoked on form submit');
};
}]);
PS: In this example I am using co called scope soup. It is simple to understand but it clusters the $scope with additional properties. It is not recommended approach now. Read about better approach here: http://www.technofattie.com/2014/03/21/five-guidelines-for-avoiding-scope-soup-in-angular.html
UPDATE
You have slight confusion in your code:
The route redirected to /, which was caught by questionsCtrl, but the relevant template had attribute ng-controller=autoQuoteCtrl. So which controller should be then used to respond to user action?? Not sure if that was intended :)
SOLUTION
The submit function should have been called like this
<form ng-submit="onSubmit()">
I forgot the () in the first example, sorry :)
html
<div ng-controller="formCtrl">
<form name="userForm" class="well form-search" >
<input type="text" ng-model="name" class="input-medium search-query" placeholder="Name" required >
<input type="email" ng-model="email" class="input-medium search-query" placeholder="Email" required >
<input type="text" ng-model="message" class="input-medium search-query" placeholder="Message" required >
<button type="submit" class="btn" ng-click="formsubmit(userForm.$valid)" ng-disabled="userForm.$invalid">Submit </button>
</form>
<pre ng-model="result">
{{result}}
</pre>
</div>
jsfile
var app = angular.module('formExample', []);
app.controller("formCtrl", ['$scope', '$http', function($scope, $http) {
$scope.url = 'submit.php';
$scope.formsubmit = function(isValid) {
if (isValid) {
$http.post($scope.url, {"name": $scope.name, "email": $scope.email, "message": $scope.message}).
success(function(data, status) {
console.log(data);
$scope.status = status;
$scope.data = data;
$scope.result = data; // Show result from server in our <pre></pre> element
})
}else{
alert('Form is not valid');
}
} }]);
click here
Trying to auto-populate first input field value into second input field value, However if the second input field as existing values then i would like to append / concatenate the first input field value to second.
logic:
if ( second ){
second = first + second;
}else{
second = first;
}
html:
<input type='text' ng-model='owner' required class="form-control">
<input type='text' ng-model='member' required class="form-control">
code:
app.controller("Controller", ['$scope', function($scope){
$scope.$watch(function () {
return $scope.owner;
},
function (newValue, oldValue) {
if ( $scope.member ){
$scope.member = $scope.owner + ',' + $scope.member;
}else{
$scope.member = newValue;
}
}, true);
}]);
plunker
Update (problem):
When i type Jake in Owner Field, it loops through the letters and print's as Jake,Jak,Ja,Jin member field. If i have pre-existing value Adam in member field, upon entering Tom in owner filed it will create Tom,To,T,Adam in member field. Please check the plunker for demo.
Mad-D consider changing your approach as it is prone to a circular dependency based on the way ng-model works.
You already have access to both values and you can display it in other ways. Plus your controller looks cleaner and acts as a true view model (vm):
Plunker
app.controller("Controller", function(){
var myCtrl = this;
myCtrl.owner = "";
myCtrl.member = "";
});
I have created a plnkr
. And also given below. Check whether it's correct one for you.
var app = angular.module('form-example1', []);
app.controller("Controller", ['$scope', function($scope){
$scope.permaMember = $scope.member?$scope.member:'';
$scope.editSecond = function(member){
$scope.permaMember = member?member:'';
}
$scope.editFirst = function(owner){
if(owner){
$scope.member = $scope.permaMember + owner
}
else{
$scope.member = $scope.permaMember
}
}
}]);
<!doctype html>
<html ng-app="form-example1">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div ng-controller="Controller">
<form name="testform">
<div class='form-group'>
<label>Owner</label>
<input type='text' ng-model='owner' required class="form-control" ng-change="editFirst(owner)">
</div>
<div class='form-group'>
<label>Member</label>
<input type='text' ng-model='member' required class="form-control" ng-change="editSecond(member)">
</div>
<button ng-disabled="testform.$invalid" ng-click ="submit()">SAVE</button>
</form>
</div>
</body>
</html>
Why not just have a 3rd read only text box or label that displays $scope.owner, $scope.member?
Hello I am at my wit's end and I've been stuck creating a more complex version of the form than the example I provide.
I have JS object that is representation of the form. I use parsley's "isValid" on the form itself (checkAll and checkGroup function). These methods are fired on every input that is marked with data-parsley-required attribute. The reason for this is I need to know the state of the whole form and it's parts so I can enable/disable step buttons.
Everything works fine but I also need to call external API when all validations have successed, see line 35. The methods checkAll and checkGroup are basically firing the events again, thus making more AJAX calls (we have limit on calls to the API). Is there a way to force method isValid to just check if the field has been validated and get true/false value out of it?
The whole thing is coded and depends on this structure so the best way would be to have similar functionality. I'm not so experienced so I make lot of mistakes. My example is very simplified version of my actual form but when you open console window you can see what I mean. Uncomment lines 32 and 33 to see the difference and you will know what I mean.
Example code
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<form action="" id="myform">
<div id="section1">
<input type="text" id="field1" data-parsley-required data-parsley-trigger="input" data-parsley-group="group1" data-parsley-lengthvalidator data-parsley-remote="http://pokeapi.co/api/v2/pokemon/1" data-parsley-remote-validator="remotevalidator" /><br />
<button id="next" disabled>Next</button><br />
</div>
<div id="section2">
<input type="text" id="field2" data-parsley-required data-parsley-trigger="input" data-parsley-group="group2" />
</div>
<input type="submit" id="submit-button" disabled />
</form>
</body>
</html>
JS:
function Form(form) {
this.form = form;
this.validations = {};
this.formValid = false;
this.checkAll = function() {
var result = $(form).parsley().isValid();
if (result) {
$('#submit-button').removeAttr('disabled');
console.log('form validated');
} else {
$('#submit-button').attr('disabled', true);
}
this.formValid = result;
};
this.checkGroup = function(e) {
var group = $(e.target).attr('data-parsley-group');
var result = $(form).parsley().isValid({group: group});
if (result) {
$('#next').removeAttr('disabled');
console.log('group validated');
} else {
$('#next').attr('disabled', true);
}
this.validations[group] = result;
};
this.initialize = function() {
var self = this;
$(this.form).parsley();
$('*[data-parsley-required]').on('input', function(e) {
self.checkAll();
self.checkGroup(e);
});
$('#field1').parsley().on('field:success', function() {
console.log('calling another API')
})
Parsley.addValidator('lengthvalidator', {
validateString: function(value) {
console.log('local validator');
return value.length > 0;
}
});
Parsley.addAsyncValidator('remotevalidator', function(response) {
console.log('remote validator');
return response.responseJSON.name === 'bulbasaur';
})
}
}
var form = new Form('#myform');
form.initialize();