At the moment I have a ui-grid with a full name and registration columns. I also have search fields for both. If user searches for registration, the table is updated 'on the fly'. My issue is that if the user enters both to narrow down the search e.g. registration and name at the same time. The table only reacts on a single filter input.
This is part of my code responsible for watching the field vm.model.employeeName and vm.model.registrationName which are the search fields. vm.resultData is an array of rows to be inserted into vm.gridOptions.data (the ui-grid).
vm.watchFilter = function() {
if (vm.model.employeeName || vm.model.registrationNumber) {
if (vm.model.employeeName) {
vm.updatedResultData = $filter('filter')(vm.resultData, {employeeFullName: vm.model.employeeName});
}
if(vm.model.registrationNumber) {
vm.updatedResultData = $filter('filter')(vm.resultData, {currentVehicleRegistration: vm.model.registrationNumber});
}
vm.gridOptions.data = vm.updatedResultData;
} else {
vm.gridOptions.data = vm.resultData;
}
vm.numberOfRecords = vm.gridOptions.data.length;
};
$scope.$watch('vm.model.employeeName', vm.watchFilter);
$scope.$watch('vm.model.registrationNumber', vm.watchFilter);
How do I combine the 2 to get narrowed down search? I've spent hours on this...
I don't want to end up with if statements for every possible search as I might add an extra search field in the future. Also if a user decides to enter reg first and then name.....
I hope this will help you. Thank you.
var app = angular.module('app', ['ngMessages']);
app.controller('pageCtrl', ['$scope', '$http', function($scope, $http) {
$scope.names = [{"Name":"Mark","Number":"10000"},
{"Name":"Steve","Number":"20000"},
{"Name":"Bill","Number":"30000"},
{"Name":"John","Number":"40000"},
{"Name":"Luis","Number":"50000"}];
$scope.search = function(){
$scope.criteria = angular.copy($scope.criteria1);
}
}]);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-messages.min.js"></script>
<div ng-app="app" class="container" >
<h1>Filter Name & Registeration Number</h1>
<hr />
<form ng-controller="pageCtrl" ng-init='getData()'>
<div class='form-group'>
<div class='row'>
<div class="right-inner-addon col-md-4 ">
<input type="search" ng-model='model.Name' class="form-control" placeholder="Name">
</div>
<div class="right-inner-addon col-md-4 ">
<input type="search" ng-model='model.Number' class="form-control" placeholder="Registeration Number">
</div>
</div>
</div>
<table class="table table-bordered" >
<tr>
<th>Name</th>
<th>Registeration Number</th>
<tr>
<tr ng-repeat="item in filtered = (names | filter : model)">
<td>{{item.Name}}</td>
<td>{{item.Number}}</td>
<tr>
</table>
</form>
</div>
Related
I have two end points
http://localhost:3000/entry (POST)
Keys are :- fname, lname and age . We can submit a form by sending a POST request to this URL.
http://localhost:3000/entries (GET)
It will return the existing data from the database in a JSON.
[
{
"_id": "5b48a137c3b2a3454b853a3c",
"fname": "John",
"lname": "Jose",
"age": "28",
"__v": 0
},
{
"_id": "5b506cc7d9105012f59c87e6",
"fname": "Alex",
"lname": "Cruz",
"age": "27",
"__v": 0
}
]
I can successfully submit a form. In my HTML, I also have a table. I want to update the data in the table whenever I submit an entry without reloading the whole page.
Actually, data in this API http://localhost:3000/entries is dynamic, sometimes, I insert into database directly. So, whenever there is a change, it should reflect in the table without reloading the whole page.
I am using AngularJS 1.
index.html :-
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="style.css">
<div ng-app="myApp">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h3>
Dashboard
</h3>
</div>
</div>
<form name="saveTemplateData" action="#" ng-controller="FormCtrl" ng-submit="submitForm()" >
<div class="col-sm-12">
<div class="form-group">
<label>FirstName</label>
<input type="text" class="form-control" value="" ng-model="form.fname" />
</div>
<div class="form-group">
<label>LastName</label>
<input type="text" class="form-control" value="" ng-model="form.lname" />
</div>
<div class="form-group">
<label>Age</label>
<input type="text" class="form-control" value="" ng-model="form.age" />
</div>
</div>
<div class="col-sm-12">
<input type="submit" class="btn btn-success" ngClick="Submit">
</div>
</form>
<!-- Table Start -->
<div class="row">
<table style="width:100%">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
</tr>
<tr>
<!-- item.fname -->
<td>{{item.fname}}</td>
<!-- item.lname -->
<td>{{item.lname}}</td>
<!-- item.age -->
<td>{{item.age}}</td>
</tr>
</table>
</div>
<!-- Table END -->
</div>
</div>
script.js :-
var app = angular.module('myApp', []);
app.controller('FormCtrl', function ($scope, $http) {
$scope.submitForm = function()
{
$http({
url: "http://localhost:3000/entry",
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $.param($scope.form)
}).then(function (response) {
$scope.status = status;
}), function (error) {
$scope.status = status;
};
}
});
If I understand your question and problem(s), you'll need to do a number of things to resolve your issues.
Firstly, you'll want to make some extensions to your controller. The main one being to fetch the data from your API:
app.controller('FormCtrl', function ($scope, $http, $interval) {
/*
Add this method to get data from server
*/
$scope.fetchData = function() {
// It is best practice to handle error responses as well (not
// shown here)
$http.get('http://localhost:3000/entries').then(function(response) {
// Set the data items in your scope. Doing this should now
// cause them to be listed in your view
$scope.items = response.data;
});
}
$scope.submitForm = function($event) {
// Adding this prevents the browser from reloading on form submit
$event.preventDefault()
$http({
url: "http://localhost:3000/entry",
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $.param($scope.form)
}).then(function (response) {
$scope.status = status;
}), function (error) {
$scope.status = status;
});
}
// Fetch data once controller is set up, on a regular 2 second
// interval
$interval(function() {
$scope.fetchData()
}, 2000)
});
You'll also need to update your HTML/view:
<!-- Add $event as an argument to you ng-submit callback -->
ng-submit="submitForm($event)"
And:
<!-- Doing this causes the data in the items array to be iterated
and displayed in a list-wise fashion in the table -->
<tr ng-repeat="item in items">
<!-- item.fname -->
<td>{{item.fname}}</td>
<!-- item.lname -->
<td>{{item.lname}}</td>
<!-- item.age -->
<td>{{item.age}}
</td>
</tr>
Finally, the most important thing is to wrap the table and form with your FormCtrl controller. You can do this by moving ng-controller="FormCtrl" from your <form> element, to your <div class="container"> element in your view.
I am struggling to understand how to implement an add-function that adds a bit of HTML-code each time I click on a plus-button. The user should be able to add how many questions he/she wants, which means each time you click the button, the new code should be added underneath the previous one. Also I want the input to be added to an array in vm.createdset.question. This is the code I want to add each time I click on a button:
<div class="form-group row question-margin">
<label for="description" class="col-md-2 col-form-label">Fråga 1</label>
<div class="col-md-10">
<textarea type="text" class="form-control" placeholder="Beskriv scenariot och frågan" name="createdset" id="createdset" ng-model="vm.createdset.question.text"></textarea>
</div>
</div>
The button-code:
<i class="fa fa-plus-circle fa-3x new" aria-hidden="true"></i>
You can do this using ng-repeat and an array. All HTML within the div containing the ng-repeat will be repeated for every item in your array.
If you want to keep track of the number of the question you could add newQuestion.id = questionList.length to $scope.addQuestion and instead of using {{$index + 1}} you'll use {{question.id}} instead.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.questionList = [];
$scope.addQuestion = function() {
var newQuestion = {};
newQuestion.content = "";
$scope.questionList.push(newQuestion);
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="addQuestion()">Add Question</button>
<hr />
<div ng-repeat="question in questionList track by $index">
<div class="form-group row question-margin">
<label for="description" class="col-md-2 col-form-label">Fråga {{$index + 1}}</label>
<div class="col-md-10">
<textarea type="text" class="form-control" placeholder="Beskriv scenariot och frågan" name="createdset" id="createdset" ng-model="question.content"></textarea>
</div>
</div>
<hr />
</div>
</div>
</body>
</html>
According to your comments, this should be what you're looking for in your particular case:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, adminService) {
var vm = this;
vm.questionList = [];
vm.addQuestion = function() {
var newQuestion = {};
newQuestion.content = "";
vm.questionList.push(newQuestion);
};
vm.save = function() {
adminService.create(vm.questionList);
};
});
app.service('adminService', function() {
var create = function(answers) {
//Handle your answers and send the result to your webserver.
console.log(answers);
}
return {
create: create
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl as controller">
<button ng-click="controller.addQuestion()">Add Question</button>
<hr />
<div ng-repeat="question in controller.questionList track by $index">
<div class="form-group row question-margin">
<label for="description" class="col-md-2 col-form-label">Fråga {{$index + 1}}</label>
<div class="col-md-10">
<textarea type="text" class="form-control" placeholder="Beskriv scenariot och frågan" name="createdset" id="createdset" ng-model="question.content"></textarea>
</div>
</div>
<hr />
</div>
<div>
<button ng-click="controller.save()">Save</button>
</div>
</div>
</body>
</html>
I am working on a web development project and I am using bootstrap tabs there. I am dynamically creating them using add and remove input field section, according to that number of inputs I am creating the tabs in the same page using ajax.
In that tabs I have the same form with same input fields. There is a input field with autocomplete function in that form. I am taking data from mysql to that field. My problem is autocomplete is only working in the first tab not in the others. Autocomplete field label is Responsible
This is my function.
function autocompletT() {
var min_length = 0;
var keyword = $('#responsible_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'ajax_refresh2.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#responsible_id_list').show();
$('#responsible_id_list').html(data);
$('#responsible_id_list li').click(function() {
var txx = $(this).text();
var tcust = $(this).val();
});
}
});
} else {
$('#responsible_id_list').hide();
}
}
// set_item : this function will be executed when we select an item
function set_item(item) {
// change input value
$('#responsible_id').val(item);
// hide proposition list
$('#responsible_id_list').hide();
}
Portion of My code
<div class="col-md-6 entire_div">
<div class="panel with-nav-tabs panel-primary">
<div class="panel-heading">
<ul class="nav nav-tabs">
<?php
for ($row = 0; $row < $agenda_size; $row++) {
$p_agenda = $mAgenda[$row];
$row_plus = $row + 1;
?>
<li><?php echo $p_agenda; ?></li>
<?php
}
?>
</ul>
</div>
<div class="panel-body">
<div class="tab-content">
<?php
for ($row = 0; $row < $agenda_size; $row++) {
$p_agenda = $mAgenda[$row];
$row_plus = $row + 1;
?>
<div class="tab-pane fade" id="<?php echo $row_plus;?>">
<!-- form -->
<form class="ws-validate">
<div class="form-group">
<label for="responsible_id" class="control-label">Responsible</label>
<input type="text" class="form-control" id="responsible_id" name="zip" placeholder="Select Responsible Person" onkeyup="autocompletT()" >
<ul id="responsible_id_list"></ul>
</div>
<div class="form-group">
<button id="submit_btn" class="btn btn-primary">Add</button>
<!-- <input id="submit_btn" type="submit" value="Add"> -->
</div>
</form>
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="mytable" class="table table-bordred table-striped">
<thead>
<th><input type="checkbox" id="checkall" /></th>
<th>Action</th>
<th>Start Date</th>
<th>Due Date</th>
<th>Status</th>
<th>Responsible</th>
</thead>
<tbody>
</tbody>
</table>
<div class="delete_b_class">
<button id="delete_row" class="btn btn-danger">Delete Row</button>
</div>
</div>
</div>
</div>
<div class="submit_all_div">
<input class="submit_all_b" id="submit" onclick="myDataSendFunction()" type="button" value="Submit">
</div>
</div>
<?php
}
?>
</div>
</div>
</div>
</div>
ids are unique
Each element can have only one id
Each page can have only one element with that id
classes are NOT unique
You can use the same class on multiple elements.
You can use multiple classes on the same element.
Probably, you are creating so many #responsible_id and #responsible_id_list with your php code.
So, as IDs must be unique. use the a unique ID for each search field (which is responsible_id ) and list (which is responsible_id_list ) here.
You can get a idea from here:- remove onkeyup="autocompletT" function from the input and add jquery event like this. then find the next responsible_id_list then populate list and append list to it.
$('.responsible_id').keyup(function(){
var min_length = 0;
var keyword = $(this).val() ;
///others codes
//say
var list='';
$(this).next('.responsible_id_list').html(list);
})
You might need to re-initialize the autocomplete on the inputs every time. Go through this question to get a braoder picture. This should solve your concerns
I want to retain the selected check boxes as is even when I am
changing my search query. Initially I am posting some query in search
and selecting one of the resulted values, Now if I change my search
query, then New values will be my result. But I want to retain the
checkbox selected for the previous values...
`
//Demo of Searching and Sorting Table with AngularJS
var myApp = angular.module('myApp',[]);
myApp.controller('TableCtrl', ['$scope', function($scope) {
$scope.allItems = getDummyData();
$scope.resetAll = function()
{
$scope.filteredList = $scope.allItems ;
$scope.newEmpId = '';
$scope.newName = '';
$scope.newEmail = '';
$scope.searchText = '';
}
$scope.add = function()
{
$scope.allItems.push({EmpId : $scope.newEmpId, name : $scope.newName, Email:$scope.newEmail});
$scope.resetAll();
}
$scope.search = function()
{
$scope.filteredList = _.filter($scope.allItems,
function(item){
return searchUtil(item,$scope.searchText);
});
if($scope.searchText == '')
{
$scope.filteredList = $scope.allItems ;
}
}
$scope.resetAll();
}]);
/* Search Text in all 3 fields */
function searchUtil(item,toSearch)
{
/* Search Text in all 3 fields */
return ( item.name.toLowerCase().indexOf(toSearch.toLowerCase()) > -1 || item.Email.toLowerCase().indexOf(toSearch.toLowerCase()) > -1 || item.EmpId == toSearch
)
? true : false ;
}
/*Get Dummy Data for Example*/
function getDummyData()
{
return [
{EmpId:2, name:'Jitendra', Email: 'jz#gmail.com'},
{EmpId:1, name:'Minal', Email: 'amz#gmail.com'},
{EmpId:3, name:'Rudra', Email: 'ruz#gmail.com'}
];
}
.icon-search{margin-left:-25px;}
<br /> <br />
<div ng-app="myApp">
<div ng-controller="TableCtrl">
<div class="input-group">
<input class="form-control" ng-model="searchText" placeholder="Search" type="search" ng-change="search()" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</span>
</div>
<table class="table table-hover data-table sort display">
<thead>
<tr>
<th class="EmpId"> <a href="" ng-click="columnToOrder='EmpId';reverse=!reverse">EmpId
</a></th>
<th class="name"> Name </th>
<th class="Email"> Email </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in filteredList | orderBy:columnToOrder:reverse">
<td><input type="checkbox" name="test" />{{item.EmpId}}</td>
<td>{{item.name}}</td>
<td>{{item.Email}}</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-xs-3">
<input type="text" ng-model="newEmpId" class="form-control" placeholder="EmpId">
</div>
<div class="col-xs-3">
<input type="text" ng-model="newName" class="form-control" placeholder="Name">
</div>
<div class="col-xs-4">
<input type="email" ng-model="newEmail" class="form-control" placeholder="Email">
</div>
<div class="col-xs-1">
<button ng-click="add()" type="button" class="btn btn-primary">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
</div>
</div> <!-- Ends Controller -->
</div>
`Fiddle
Try to add ng-model="item.selected" to your checkbox tag
<td><input ng-model="item.selected" type="checkbox" name="test" />{{item.EmpId}}</td>
Works for me, hope it helps.
Looks like this is happening because you are resetting the items here:
if($scope.searchText == '')
{
$scope.filteredList = $scope.allItems ;
}
and allItems doesn't tell anywhere if the checkbox needs to be selected on not. I would suggest you to update the code where you are creating the checkboxes, something like:
<td><input type="checkbox" name="test" ng-model=item.selected ng-checked=item.selected/>
Note that I have updated the item to have a 'selected' field which will tell if that item is selected or not(default could be false). While creating the checkbox I have linked the model using ng-model=item.selected
Updated fiddle at http://jsfiddle.net/3a3zD/194/
I need to fill my trip table with data from two sources: from server using GET when the page loads (to have user's archive trips) and from observable values (when a user adds a new trip). Can I somehow merge those two scripts so that they apply bindings only once? Right now I get an error: You cannot apply bindings multiple times to the same element
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Add a trip</h3>
</div>
<div class="panel-body">
<div class="form-group">
<label for="from">From</label>
<input type="text" class="form-control" id="from" name="from" placeholder="From" data-bind="value: from">
</div>
<div class="form-group">
<label for="to">To</label>
<input type="text" class="form-control" id="to" name="to" placeholder="To" data-bind="value: to">
</div>
<a class="btn btn-primary btn-lg" role="button" data-bind="click: add()" >Add</a>
</div>
</div>
<div class="panel panel-default">
<div class=panel-heading>Your trips</div>
<table class=table>
<thead>
<tr>
<th>From</th>
<th>To</th>
</tr>
</thead>
<tbody data-bind="foreach: records">
<tr>
<td data-bind="text: from"></td>
<td data-bind="text: to"></td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript" src="js/knockout-3.4.0.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
var AppViewModel = function() {
this.from = ko.observable();
this.to = ko.observable();
this.records = ko.observableArray();
};
var model = new AppViewModel();
model.add = function() {
model.records.push({
from: model.from(),
to: model.to()
});
//sending data to server
var data =
{
from : this.from(), to : this.to(), date : this.date(), price : this.price(), freeSeats : this.freeSeats()
}
alert(data);
$.post("/data", data, function(response)
{
})
}
ko.applyBindings(model);
</script>
<script>
function tripModel() {
this.records = ko.observableArray([]);
$.getJSON("/usersTrips", function(data) {
self.records(data);
})
}
ko.applyBindings(new tripModel());
</script>
Give the relevant elements IDs and then apply the models to only those DOM elements. For example,
Html:
<div id="add-trip" class="panel panel-default">
<div id="your-trips" class="panel panel-default">
And the binding:
ko.applyBindings(model, document.getElementById("add-trip"));
ko.applyBindings(new tripModel(), document.getElementById("your-trips"));
JSFiddle Example:
https://jsfiddle.net/hellobrett/49xaqj46/1/
JSFiddle example going the other direction:
https://jsfiddle.net/hellobrett/49xaqj46/2/
Reference:
http://knockoutjs.com/documentation/observables.html
In case you’re wondering what the parameters to ko.applyBindings do,
The first parameter says what view model object you want to use with the declarative bindings it activates
Optionally, you can pass a second parameter to define which part of the document you want to search for data-bind attributes. For example, ko.applyBindings(myViewModel, document.getElementById('someElementId')). This restricts the activation to the element with ID someElementId and its descendants, which is useful if you want to have multiple view models and associate each with a different region of the page.