AngularJS: Creating Query Form for Database - javascript

So I am having a little problem creating a very simple query form due to my lack of understanding about coding. As you can see in the app.js below, I have FormController, which retrieves information from the form, feeds it into the jsonUrlGen function which creates a custom URL, which is then sent to my SolrController which accesses that URL and pulls the JSON information from it.
However it is quite clear after taking a step back and looking at it that the structure of my code is wrong, and I am missing an app.service to link the shared variables between my two controllers. I'm also not even sure if I need two controllers in this instance, but it just happened as I was coding it.
If anybody can tell me what I'm doing wrong here I would really appreciate it, because the code just flat out does not work.
Thanks.
.HTML FILE
<html ng-app="solrApp">
<head>
<link link rel="stylesheet" href="bootstrap-3.3.5-dist/css/bootstrap.min.css" />
<link link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.3/angular.min.js"></script>
<script type= "text/javascript" src="app.js"></script>
</head>
<body>
<!--<h1 class="headline">Logo or Something Here</h1>-->
<div class="logo"><img src="images/CubedE.png" id="cubedE"/></div>
<div class = "queryForm" ng-controller="FormController">
<input type="text" class="queryBox" id="mainQueryString" placeholder="Query String" ng-model="fullQuery.queryString"><br />
<input type="text" class="queryBox" placeholder="Filter Query" ng-model="fullQuery.filterQuery"><br />
<input type="text" class="queryBox" placeholder="Sort By" ng-model="fullQuery.sortBy"><br />
<h2>Extract only from rows:</h2>
<input type="text" class="halfQueryBox" placeholder="Start" ng-model="fullQuery.startRow"><input type="text" class="halfQueryBox" placeholder="End" ng-model="fullQuery.endRow"><br />
<input type="text" class="queryBox" placeholder="Field List (Separate by comma)" ng-model="fullQuery.fieldList"><br />
<input type="text" class="queryBox" placeholder="Raw Query Parameters (key1=val1&key2=val2)" ng-model="fullQuery.rawQuery"><br />
<button type="button" ng-click="jsonUrlGen()">Submit Query</button>
</div>
<div class = "results" ng-controller="SolrController">
<ul>
<li ng-repeat="item in items">
{{ item.key }} - <em>{{ item.value }}</em>
</li>
</ul>
</div>
</body>
</html>
APP.JS
(function(){
var app = angular.module('solrApp', []);
app.controller('FormController', function($scope) {
$scope.fullQuery = {
queryString: '',
filterQuery: '',
sortBy: '',
startRow: '',
endRow: '',
fieldList: '',
rawQuery: ''
}
$scope.jsonUrlGen = function(){
var jsonURL = "http://localhost:8983/solr/core/select?";
if($scope.fullQuery.queryString !== '') {
jsonURL = jsonURL + "q=" + $scope.fullQuery.queryString;
}
else if($scope.fullQuery.filterQuery !== '') {
jsonURL = jsonURL + "&fq=" + $scope.fullQuery.filterQuery;
}
else if($scope.fullQuery.sortBy !== '') {
jsonURL = jsonURL + "&sort=" + $scope.fullQuery.sortBy;
}
else if($scope.fullQuery.startRow !== '') {
jsonURL = jsonURL + "&start=" + $scope.fullQuery.startRow;
}
else if($scope.fullQuery.endRow !== '') {
jsonURL = jsonURL + "&rows=" + $scope.fullQuery.endRow;
}
else if($scope.fullQuery.fieldList !== '') {
jsonURL = jsonURL + "&fl=" + $scope.fullQuery.fieldList;
}
else {
return "exception thrown";
}
jsonURL = jsonURL + "wt=json";
return jsonURL;
};
});
app.controller('SolrController', function($scope, $http){
$http.get($scope.jsonUrlGen)
.then(function(res){
$scope.items = res.data;
});
});
})();

Answers may be opinionated since there are multiple ways to accomplish this.
I would advise to restructure html. Have a single controller that wraps the "form" and the contents of SolrController. Also the "form" should really become a <form>. In angular there is a default controller created for this tag and it helps a lot with managing validation and handling submit.
<div class="results" ng-controller="SolrController">
<form class="queryForm" name="queryForm" ng-submit="submit()">
<input type="text" class="queryBox" id="mainQueryString" placeholder="Query String" ng-model="fullQuery.queryString"><br />
<input type="text" class="queryBox" placeholder="Filter Query" ng-model="fullQuery.filterQuery"><br />
<input type="text" class="queryBox" placeholder="Sort By" ng-model="fullQuery.sortBy"><br />
<h2>Extract only from rows:</h2>
<input type="text" class="halfQueryBox" placeholder="Start" ng-model="fullQuery.startRow"><input type="text" class="halfQueryBox" placeholder="End" ng-model="fullQuery.endRow"><br />
<input type="text" class="queryBox" placeholder="Field List (Separate by comma)" ng-model="fullQuery.fieldList"><br />
<input type="text" class="queryBox" placeholder="Raw Query Parameters (key1=val1&key2=val2)" ng-model="fullQuery.rawQuery"><br />
<button ng-disabled="queryForm.$invalid">Submit Query</button>
</form>
<ul>
<li ng-repeat="item in items">
{{ item.key }} - <em>{{ item.value }}</em>
</li>
</ul>
</div>
Mind name attribute for the form. It will help to access the form in the scope. Actually when there is a name angular creates $scope.queryForm in parent controller
By default all buttons (and <input type="submit") on form submit on click. But type="button" will prevent it. So remove it
Controller SolrController. It's inappropriate to perform a request before user had a change to input something. $http.get should work on a click handler which we choose to be submit event.
app.controller('SolrController', function($scope, $http){
$scope.fullQuery = {};//ng-model will take care of creating all properties
function jsonUrlGen(){ //same code here
}
$scope.submit = function(){
$http.get(jsonUrlGen())
.then(function(res){
$scope.items = res.data;
});
});
};
})
Hope this helps

Related

How access form in ng-repeat?

Here is clear exampel about forms:
<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">
<input type="text"
name="input_{{$index}}_0"></input>
<!-- ... -->
Ok, but how I should access $valid field from form? E.g this does not work:
{{namesForm_$index.$valid}}
Even {{namesForm_$index}} outputs 0.
It is need to "inline" $index before {{}} resolve a variable name. How to do that?
It's not easy to get it inside of single {{ }} expression, but if you only want to use it in directives accepting expressions without handlebar (like ng-disabled), you can achieve that:
<div ng-app>
<ng-form name="namesForm_{{$index}}" ng-repeat="name in [1, 2]">
<input type="text"
placeholder="{{$index}}"
ng-required="true"
ng-model="test"
name="hey" />
<button ng-disabled="!namesForm_{{$index}}.$valid">
send
</button>
<br />
</ng-form>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
{{ IsFormValid($index) }}
$scope.IsFormValid = function(index) {
var form = angular.element("formName" + index);
return form.$valid;
};
UPDATED
Working example:
{{ IsFormValid($index) }}
$scope.IsFormValid = function(index) {
var form = angular.element(document.getElementById('#bucketForm-' + index);
return form.$valid;
};
New Approach
The below is an example for dynamic ngModel, same can be replicated for form name :
$scope.formData = {};
$scope.formData = {
settings:
{
apiEndpoint: '',
method: 'get'
},
parameters: {}
};
<div class="form-group" ng-repeat="parameter in apiParameters">
<label for="{{parameter.paramName}}" class="col-sm-2 control-label">{{parameter.paramTitle}}</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="{{parameter.paramName}}" id="{{parameter.paramName}}" ng-model="formData.parameters[parameter.paramName]" placeholder="{{parameter.paramTitle}}">
</div>
</div>

How to send multiple forms data in one shot to server using angularjs?

Hi I am developing web application in angularjs. I have two forms in one html page. Below is the structure.
<form name="form1">
<input type="text" name="fname" />
<input type="text" name="lname" />
<input type="submit" value="Next" />
</form>
<form name="form2">
<input type="text" name="address" />
<input type="text" name="state" />
<input type="submit" value="Next" />
</form>
On clicking on the next submit button of first form i want to validate first form and i want to scroll to second form and disable the first form.
On clicking on the next submit button of form2 i want to validate second form and i want to submit data to server using $http from both forms(form1 and form2).
May i know is this is possible to achieve this? Also may i know is this is the right way i am following or something else i have to do with above requirement? Any suggestion or help would be greatly appreciated. Thank you.
You can bind all your values to a common object. I am enabling the second form after submitting the first form. In second forms submit function, you just have to loop through the values of common object and append it to formData. If you don't have any reason for having two forms, you can consolidate it into one.
Note: I have not added any form validations. For adding form validations, please refer https://codepen.io/sevilayha/pen/xFcdI
HTML:
<form name="form1" ng-submit="enableForm2()">
<input type="text" name="fname" ng-model="obj.fname" />
<input type="text" name="lname" ng-model="obj.lname" />
<input type="submit" value="Next" />
</form>
<form name="form2" ng-show="enableForm" ng-submit="finalSubmit()">
<input type="text" name="address" ng-model="obj.address" />
<input type="text" name="state" ng-model="obj.state" />
<input type="submit" value="Next" />
</form>
JS:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$scope.obj = {};
$scope.enableForm = false;
$scope.enableForm2 = function() {
$scope.enableForm = true;
}
$scope.finalSubmit = function() {
$http({
method: 'POST',
url: YourURL,
withCredentials: true,
headers: {
'Content-Type': undefined
},
data: {},
transformRequest: function(data, headersGetter) {
var formData = new FormData();
angular.forEach($scope.obj, function(value, key) {
formData.append(key, value);
})
return formData;
}
}).then(function(data) {
$scope.enableForm=false;
}).catch(function(data, status) {
})
}
});
You can acheive it vai an Ajax Call not by direct Submit. Moreover Form Submit is not required. (Adding Form tag is optional)
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
<!-- Angular Material Library -->
<script src="http://ajax.googleapis.com/ajax/libs/angular_material/1.0.4/angular-material.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p>Personal Info</p>
<input type="text" ng-model="form1.fname" name="fname"/>
<input type="text" ng-model="form1.lname" name="lname"/>
<input type="button" ng-click="SubmitForm()" value="Next"/>
<p>Address Info</p>
<input type="text" ng-model="form2.address" name="address"/>
<input type="text" ng-model="form2.state" name="state"/>
<input type="button" ng-click="SubmitForm()" value="Next"/>
</div>
<script>
var app = angular.module('myApp', ['ngMaterial']);
app.controller('myCtrl', function ($scope, $http, $q, HTTPService) {
$scope.form1 = {
fname: '',
lname: ''
};
$scope.form2 = {
address: '',
state: ''
};
$scope.SubmitForm = function () {
let submitFormData = {
form1: $scope.form1,
form2: $scope.form2
};
HTTPService.SubmitData(submitFormData);
}
});
app.factory('HTTPService', function ($http, $q) {
return {
SubmitData: function (formData) {
let apiUrl = 'http://localhost:2000/...';
var req = {
method: 'POST',
url: apiUrl + "SaveData.php",
headers: {
"Content-Type": "application/json",
"Authorization": '',
"Access-Control-Allow-Origin": "*"
},
data: formData
};
var result = $http(req)
.then(function(response) {
return angular.fromJson(response.data);
}, function(response) {
return null;
});
return result;
},
};
});
</script>
</body>
</html>
Using $scope also you will get values of fields which are not in same form.
HTML Code
<div ng-app="App" ng-controller="Ctrl">
<form name="myForm">
<!-- first nested form -->
<div ng-form="form1">
<label><p>Personal Info</p></label>
<input type="text" name="fname" ng-model="myForm.fname"/>
<input type="text" name="lname" ng-model="myForm.lname"/>
</div>
<!-- second nested form -->
<div ng-form="form2">
<label><p>Address Info</p></label>
<input type="text" name="address" ng-model="myForm.address"/>
<input type="text" name="state" ng-model="myForm.state"/>
</div>
<!-- etc. -->
<input type="submit" ng-click="SubmitForm()" value="Next"/>
</form>
</div>
JS/Controller code
var app = angular.module('App');
app.controller('Ctrl', function ($scope) {
$scope.SubmitForm = function () {
var SubmitForm = $scope.myForm;
console.log(SubmitForm);
}
});
You can do someting like below
<form name="form1" ng-submit="moveNext(user)">
<input type="text" ng-model="user.fname" name="fname" required/>
<input type="text" ng-model="user.fname" name="lname" required/>
<input type="submit" value="Next"/>
</form>
<form name="form2" ng-submit="submit(addressData)">
<input type="text" ng-model="addressData.address" name="address"/>
<input type="text" ng-model="addressData.state" name="state"/>
<input type="submit" value="Next"/>
</form>
and in Controller
$scope.userDetails = {};
$scope.addressDetails = {};
$scope.moveNext = function(userData){
$scope.userDetails = userData //Save user Data here and implement logic to scroll to next form and validation
}
$scope.submit = function(addressData){
$scope.addressDetails = addressData;
// and validate the form and Submit data to server here as per your requirement
}

combined properties in expression angularjs

I have a controller with contact object in his scope.
If the contact has first name or last name, I want to show first-name<space>last-name.
My problem is that when the contact has no first name or last name. In this situation I want to show the user Create new contact but because there is a space between the first name and last name in the expression, it displays only the spacing.
Start typing in the inputs and you will that, basically, both of divs should show the same.
angular.module('myApp', []).
controller('ctrl', function($scope) {
//$scope.contact = {
// FirstName: 'first',
// LastName: 'last'
//}
$scope.contact = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{contact.FirstName + ' ' + contact.LastName || 'Create new contact'}}<br />
{{contact.FirstName + contact.LastName || 'Create new contact'}}
</div>
You can use ng-if to fix your issue.
I have updated the code to match your requirements. Hope this helps.
angular.module('myApp', []).
controller('ctrl', function($scope) {
//$scope.contact = {
// FirstName: 'first',
// LastName: 'last'
//}
$scope.contact = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{contact.FirstName + ' ' + contact.LastName}}
<span ng-if="(contact.FirstName == null || contact.FirstName == '') && (contact.LastName == null || contact.LastName == '')">Create New Contact</span>
</div>
There can be many ways this can be achieved. But since you want to achieve this in expressions only it can be done as below.. Just use the trim() in the expression.
Second solution:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{(contact.FirstName + ' ' + contact.LastName).trim() || 'Create New Contact'}}
</div>
If I understand your question correctly you can just use ng-show/ng-hide:
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-show="contact.FirstName && contact.LastName">
{{contact.FirstName + ' ' + contact.LastName}}
</span>
<span ng-hide="contact.FirstName && contact.LastName">
Create new contact
</span>
</div>
Is that what you were looking for?
You here have 2 options 1 create a function that return true or false if you have first or last name or do the verification into html:
Solution 1:
angular.module('myApp', []).
controller('ctrl', function($scope) {
$scope.contact = {};
$scope.verifyContacts = function(){
return contact.FirstName || contact.LastName;
}
});
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-hide="verifyContacts()">Create new contact</span>
<span ng-show="verifyContacts()">{{contact.FirstName + ' ' + contact.LastName}}</span>
</div>
Soution 2:
This soution will invole to write the expresion form the verifyContacts function from above solution inline so your html will look like:
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-hide="contact.FirstName || contact.LastName">Create new contact</span>
<span ng-show="contact.FirstName || contact.LastName">{{contact.FirstName + ' ' + contact.LastName}}</span>
</div>
I personally prefer the first solution.
Edit: presenting the third solution:P
Solution 3:
You can add a space at the end of the first name if the first name is available so you don't need to concat the strings with space
angular.module('myApp', []).
controller('ctrl', function($scope) {
$scope.contact = {};
contact.FirstName = contact.FirstName ? contact.FirstName + ' ' : contact.FirstName;
}
});
<div> {{contact.FirstName + contact.LastName || 'Create new contact'}} </div>
this will work but as you can see in your code that the input fields are not displayed so you most probably will need a back-end function for that or something.

Edit the form and new form add text throw angular js

Hi ,
I m write a code I m showing the two section and one form for add new text in my projects.
But i have two major Problem .
is if i click to edit button than show the form but if i change any text in form than i click to save button there is a nothing happen .
is if i fill the data in new form and just press submit button not add the data in my top li Please check this and solve my problem .
Thanks in advanced
Please help me
My Code is here
Angular Code is this
var app = angular.module('myApp', []);
app.controller('mySearchController', function($scope) {
$scope.searhBars = [{
title: "fiel 1",
description: 'What do you want'
}, {
title: "fiel 2",
description: "I want to this"
}, {
title: "fiel 3",
description: "Why do you want me "
}];
$scope.formSubmit = function(searhBar) {
showForm = false;
};
$scope.newItemAdd = function(title, description) {
if (this.newName === '') return;
$scope.searhBar.push({
title: title,
description: description
});
this.newName = '';
this.newDes = '';
};
});
HTML Code is
<body ng-app="myApp">
<ul ng-controller="mySearchController">
<li>Hello</li>
<li ng-repeat="searhBar in searhBars">
<h4 ng-show="!showForm">{{searhBar.title}}</h4>
<p ng-show="!showForm">{{searhBar.description}}</p>
<button ng-show="!showForm" ng-click="showForm=true">Edit me</button>
<form ng-submit="formSubmit(searhBar)" ng-show="showForm">
<label>Field 1.
<input type="text" ng-model="searhBar.title" />
</label>
<label>Enter Description
<textarea ng-model="searhBar.description"></textarea>
</label>
<input type="submit" value="Save" />
</form>
</li>
<li>
<form ng-submit="newItemAdd(newName, newDes)">
<label>Field
<input type="text" ng-model="newName" />
</label>
<label>Enter Description
<textarea ng-model="newDes"></textarea>
</label>
<input type="submit" value="submit" />
</form>
</li>
</ul>
</body>
Demo is
Is this what you wanted?
http://plnkr.co/edit/9ginpPiLUaVyEPdpu32f?p=preview
I fixed this part:
$scope.formSubmit = function(){
this.showForm = false;
};
$scope.newItemAdd = function(title, description){
if(this.newName === '') return ;
$scope.searhBars.push({
title:title,
description:description
});
this.newName= '';
this.newDes= '';
};
And this one:
<input type="submit" ng-click="formSubmit()" />
Oh, I also fixed this:
<label>Field {{$index + 1}}:
In order to display the correct number of the field.
Typo: $scope.searhBar[s].push({
for close form
<form ng-submit="formSubmit(searhBar); showForm=false"
http://plnkr.co/edit/Vq3U3sCcp4OeZlH1iXyM?p=preview
You need to write:
$scope.formSubmit = function(searhBar){
this.showForm = false;
};

I can't reach dynamic inputs with javascript

I want to change Cloudera Hue project code but I have some problems.
Knockout data-bind is created some html codes with foreach , when I want to reach input in this html, my code does not work correct. My app.mako file code :
.....
<div data-bind="foreach: submissionVariables" style="margin-bottom: 20px">
<div class="row-fluid">
<span data-bind="text: name" class="span3"></span>
<input type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }" class="span9" />
<button class="btn fileChooserBtn" data-bind="click: $root.showTimePicker">time</button>
</div>
</div>
<input type="text" value="2014/03/15 05:06" id="datetimepickerz"/>
....
<script src="/static/js/jquery.datetimepicker.js"></script>
<script type="text/javascript">
$('#dtpickerfolder').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
$('#dtpickereverything').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
$('#datetimepickerz').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
</script>
Output:
<input id="dtpickerfolder" class="span9" type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }"></input>
<input id="dtpickereverything" class="span9" type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }"></input>
<input id="datetimepickerz" type="text" value="2014/03/15 05:06"></input>
datetimepickerz input works correct but my dynamic inputs that ids starts with dtpicker are not working.
Can anyone help me ?
I solve this with :
self.runOrShowSubmissionModal = function runOrShowSubmissionModal() {
var script = self.currentScript();
if (! $.isEmptyObject(script.getParameters())) {
self.submissionVariables.removeAll();
$.each(script.getParameters(), function (key, value) {
self.submissionVariables.push({'name': key, 'value': value});
// CALL TO JQUERY
$("#dtpicker"+key).datetimepicker({value:"2015/04/15 05:03",step:10});
});
$("#runScriptBtn").button("reset");
$("#runScriptBtn").attr("data-loading-text", $("#runScriptBtn").text() + " ...");
$("#submitModal").modal({
keyboard: true,
show: true
});
} else {
self.runScript();
}
};
I sent my jquery in knockout function.

Categories