Angular search in a table - html

I want to make a search on the column SN in a table.
there many information in my table, I want to be able to search based on SN but when I add the filter it does not even load my table
This is what I did:
in My controler my List is filled :
$scope.List = {};
MyServices.getList()
.success(function (data) {
angular.forEach(data, function (value, index) {
$scope.List[value.SN] = {
Description: value.Description,
SN: value.SN
}
});
})
.error(function (error) {
$scope.status = 'Unable to load customer data: ' + error.message;
});
and this is my HTML:
<label>Search: <input ng-model="search.SN"></label>
<tr ng-repeat="V in List| filter:search">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>

You must write as follow:
<label>Search: <input ng-model="search.SN"></label>
<tr ng-repeat="V in List| filter: {SN: search.SN}">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>

Remove the object declaration on the input field. It will match the whole object for your specified value on the input field:
<label>Search: <input ng-model="search"></label>
<tr ng-repeat="V in List| filter: search">
<td>{{V.SN}}</td>
<td>{{V.Description}}</td>
</tr>

Related

Change part of an attribute after cloning with jQuery

I have a table with different inputs. Using a button, I want to clone the last row of the table, and add it to the table. Furthermore, I want to replace the "index" in the name with the variable of the index.
How can I replace the string "index" with the variable index?
In this example I just show one input, because it is sufficient to get a clue.
<table class='taskTable'>
<tr>
<td>
<input name='data[index][description]'></input>
<input name='data[index][text]'></input>
<input name='data[index][date]'></input>
</td>
</tr>
</table>
<button type='button' class='addTask'>Add Row</button>
<script>
var index = 1;
$(".addTask").on('click', function(){
index = index+1;
var lastTr = $('.taskTable').find('tr:last').clone();
//replace now the string index of the name with the variable
$('.taskTable').append(lastTr);
});
</script>
Here is a link to the jsFiddle
https://jsfiddle.net/tg53c96m/
Set the name with .attr("name", value):
var newName = `data[${index}][description]`;
lastTr.find("input").attr("name", newName);
Or if you want to search/replace:
lastTr.find("input").attr("name",
(i, oldName) => oldName.replace(/\[.*\]\[/, `[${index}][`));
var index = 1;
$(".addTask").on('click', function() {
index = index + 1;
var lastTr = $('.taskTable').find('tr:last').clone();
lastTr.find("input").attr("name",
(i, oldName) => oldName.replace(/\[.*\]\[.*\]$/, `[${index}][description]`));
console.log("New name: ", lastTr.find("input").attr("name"));
$('.taskTable').append(lastTr);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class='taskTable'>
<tr>
<td>
<input name='data[index][description]'>
</td>
</tr>
</table>
<button class='addTask'>Add Row</button>
Update
Just saw the edited HTML so here's the added function to handle multiple inputs with different names:
lastTr.find('input').each(function() {
let nameText = $(this).attr('name');
let newName = nameText.split('index').join(rows);
$(this).attr('name', newName);
});
In order to change the pattern of each name without having to remember which one is which is to handle only the portion of the names that actually changes:
let newName = nameText.split('index').join(rows);
nameText is the current input name which is s String value of either:
'data[index][description]',
'data[index][text]',
/* OR */
'data[index][date]'
When .split() into an Array of Strings, it removes the text: "index":
nameText.split('index')
// Returns ['data[', '][`description or text or date`]']
Finally .join() will convert the Array of Strings into a String with the variable index number between them:
.join(index)
// Returns `'data['+index+'][`description or text or date`]'`
Add the following statement as the first line of the function:
let rows = $('.taskTable tr').length;
This will be the number of rows already in the table.
Add this after the row has been cloned but before it is appended:
lastTr.find('input').attr('name', 'data' + rows);
This finds the input nested within the new row and assign it name="data'+rows. I'm not sure what's with the [description] part of the name. Is it dynamic or literal like the [index] part. It sounds like something isn't quite right about those names...
Note: The rest of the name can be whatever, I just feel wrong to have a name looking like that. The contacted string will look like the following with the original text:
lastTr.find('input').attr('name', 'data[' + rows + '][description]');
Also, I added another function that will change all row input with the new naming pattern.
Demo
/*
This will change all row input names from
'data[index][description]'
'data[index][text]'
'data[index][date]'
to
'data['+index+'][description]'
'data['+index+'][text]'
'data['+index+'][date]'
index = 0,...N
*/
$('.addTask tr').each(function(index) {
$(this).find('input').each(function() {
let nameText = $(this).attr('name');
let newName = nameText.split('index').join(index);
$(this).attr('name', newName);
});
});
$(".addTask").on('click', function(index) {
let rows = $('.taskTable tr').length;
const lastTr = $('.taskTable').find('tr:last').clone();
lastTr.find('input').each(function() {
let nameText = $(this).attr('name');
let newName = nameText.split('index').join(rows);
$(this).attr('name', newName);
});
$('.taskTable').append(lastTr);
});
<table class='taskTable'>
<tr><td>
<input name='data[index][description]'>
<input name='data[index][text]'>
<input name='data[index][date]'>
</td></tr>
<tr><td>
<input name='data[index][description]'>
<input name='data[index][text]'>
<input name='data[index][date]'>
</td></tr>
</table>
<button class='addTask' type='button'>Add Row</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Unable to Reference Nested JSON Object with KnockoutJS

I have a JSON string that has a nested JSON object called data. I am trying to reference the status portion of the nested JSON object, but when I refer to it in my HTML, KnockoutJS does not populate the cells pertaining to Status in my table. KnockoutJS does, however, populate the sender portion of the table.
JSON:
[{"statusmsg":"OK","data":{"status":"running"},"sender":"hostname","statuscode":0}]
KnockoutJS (service.js):
function ServiceViewModel() {
var self = this;
self.rows = ko.observableArray();
$.ajax({
method: "GET",
url: "/mcollective/service/status/servicename",
success: function(data) {
var observableData = ko.mapping.fromJSON(data);
var array = observableData();
self.rows(array);
}
});
};
$(document).ready(function() {
ko.applyBindings(new ServiceViewModel());
});
HTML:
<tbody data-bind="foreach: rows">
<tr>
<td data-bind="text: sender"></td>
<td>
<span data-bind="text: data.status,
css: { 'label-success': data.status == 'running',
'label-danger': data.status == 'stopped',
'label': true }">
</span>
</td>
<td>
</tr>
</tbody>
Note: I am also using Bootstrap for the CSS.
I have checked Firefox web developer console and there are no errors pertaining to my script.
The mapping plugin turns your properties into observables.
This means that our data.status property will be a ko.observable which is a function what you need to call without any arguments to get its value.
So you need to fix your css binding and write data.status() there:
<span data-bind="text: data.status,
css: { 'label-success': data.status() == 'running',
'label-danger': data.status() == 'stopped',
'label': true }"></span>

tablesorter select box with a custom match function

I have an HTML table with a column, in which an unordered list of strings is present. I am using tablesorter with the filter plugin to interact with the list. I want each string in all cells of the column to be present in a select filter in the header of the table. If the user selects an option, those rows should be displayed, where this string appears in the unordered list of the particular column cell.
Let me give you an example. I have the following list:
<table>
<thead>
<tr>
<th>name</th>
<th>profession</th>
</tr>
</thead>
<tbody>
<tr>
<td>Carl</td>
<td>
<ul>
<li>Builder</li>
<li>Professor</li>
</ul>
</td>
</tr>
<tr>
<td>Lisa</td>
<td>
<ul>
<li>Programmer</li>
<li>Professor</li>
</ul>
</td>
</tr>
</tbody>
</table>
In the table header, I want tablesorter to display a select box with the three professions. If, say, professor is selected, both rows should be shown. If programmer is selected, only Lisa would appear. How would I reach that?
Use the filter_functions widget option as follows (demo):
$(function () {
$('table').tablesorter({
theme: 'blue',
widgets: ['filter'],
widgetOptions: {
filter_functions: {
1: {
"Programmer": function (e, n) { return /programmer/.test(n); },
"Professor" : function (e, n) { return /professor/.test(n); },
"Builder" : function (e, n) { return /builder/.test(n); }
}
}
}
});
});
Update: If you don't want to hardcode because the professions vary, then you can use the filter_selectSource option to grab all of the column text, extract out each item from the list then return it as an array (demo):
HTML (make sure to include these class names)
<th class="filter-select filter-match">profession</th>
Script
$(function () {
$('table').tablesorter({
theme: 'blue',
widgets: ['filter'],
widgetOptions: {
filter_selectSource: function (table, column, onlyAvail) {
// get an array of all table cell contents for a table column
var arry = [],
array = $.tablesorter.filter.getOptions(table, column, onlyAvail);
// split content if multiple professions are encountered
$.each( array, function(i, n){
// look for carriage returns; split into two separate professions
if (/\n/.test(n)) {
n = n.split(/\n/);
}
arry.push(n);
});
// flatten array
return $.map(arry, function(n){ return n; });
}
}
});
});

Using angularjs, how to perform math operations on textboxes and see result as the values are being typed in?

I have an HTML file with 2 textboxes, one for value and the other for quantity. The result text at the bottom multiplies value with quantity and show the result.
The intention is to show the sum of all the rows of pairs of textboxes on the screen. To that end, I have an "add new" button which keeps adding additional pairs of textboxes.
The first set of textboxes that appear on the HTML, reflect the size of the "numbers" array of objects containing properties "val" and "qty". The same values are bound to the textboxes.
However, only the first set of values are added on screen. As I keep adding new textboxes and entering new values, the value of the result should change accordingly, but it simply doesn't.
HTML Code
<div ng-app="adder" ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-model="number.val"></td>
<td><input type="text" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>pp',[]);
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{sum}}
</div>
</body>
</html>
Javascript
var myapp = angular.module('adder', []);
myapp.controller('addcontrol',function($scope){
$scope.numbers = [
{val:100,
qty:200,
}
];
$scope.add = function()
{
$scope.numbers.push({val:0,qty:0});
};
$scope.deleteNumber = function(val)
{
numbers.splice(val, 1);
};
var result=0;
angular.forEach($scope.numbers, function(num){
result+=(num.val * num.qty);
});
$scope.sum = result;
});
What am I doing wrong here?
In your code, the calculation of the sum would only be executed once.
You need to add a watch of the scope or bind a function to ng-change event in order to keep the sum updated while you change the numbers.
For example, you can do:
<div ng-app="adder" ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-change="update()" ng-model="number.val"></td>
<td><input type="text" ng-change="update()" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>pp',[]);
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{sum}}
</div>
And:
var myapp = angular.module('adder', []);
myapp.controller('addcontrol', function($scope) {
$scope.numbers = [{
val: 100,
qty: 200,
}
];
$scope.add = function() {
$scope.numbers.push({
val: 0,
qty: 0
});
};
$scope.deleteNumber = function(val) {
numbers.splice(val, 1);
$scope.update();
};
$scope.update = function() {
var result = 0;
angular.forEach($scope.numbers, function(num) {
result += (num.val * num.qty);
});
$scope.sum = result;
};
});
I know this a little bit besides the question but you can do arbitrary arithmetic operations inside a single input field:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="">
<input ng-model="expression"/>
<p>{{$eval(expression)}}</p>
</body>
Based on Pylinux's answer: it may seem obvious, however here it is. If you want to add 2 expressions, use the following:
{{$eval(expression1)+ $eval(expression2) }}
The code in your controller is only activated once (when the view is rendered). Therefore, your sum is only computed once, before you even get a chance to add any rows. What you need to do is put your calculation into a function so that it can be called repeatedly as needed.
Tong's answer is basically correct, but I think this is a nicer way to do it:
<div ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-model="number.val"></td>
<td><input type="text" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{total()}}
</div>
and
var app = angular.module('app', [])
.controller('addcontrol', function($scope) {
$scope.numbers = [{
val: 100,
qty: 200,
}];
$scope.add = function() {
$scope.numbers.push({
val: 0,
qty: 0
});
};
$scope.deleteNumber = function(val) {
$scope.numbers.splice(val, 1);
};
$scope.total = function(){
var total = 0;
angular.forEach($scope.numbers, function(num) {
total += (num.val * num.qty);
});
return total;
}
})
Define a total function that loops through the array and returns the appropriate sum. Then you can bind that function to the result field in the view. The benefit of doing it this way is that you don't have to remember to call update() everywhere that might cause the total to change (like ng-change on the textboxes, and in the deleteNumber function). The total just updates automatically.
Here's a demo.
Php
Create a database named as students(using cmd)
Create a table named as tbl_students_info with column:
id, data type is int with size of 11, auto increment and set as primary key
Firstname, data type is varchar with size of 30
Middlename, data type is varchar with size of 30
Lastname, data type is varchar with size of 30
Contact, data type is int with size of 11
House_address, data type is int with size of 50
Create a webpage that contains 5 textbox and 1 button. 1st textbox is for firstname, 2nd textbox is for middlename, 3rd textbox is for lastname, 4th textbox is for contact, last textbox is for house_address and button for saving the input data in those texboxes to database
Angular
Create a calculator that computes the sum of 2 numbers, product of 2 numbers, difference of 2 numbers and quotient of 2 numbers. The web page must contain 2 textbox and 4 buttons for the operations.
Create a wepage that computes the area of a triangle. Must have 2 textbox and a button for calculate area.
Create a website that calculate the age of the user. Must have a textbox and a button, textbox is for input birth year and button for compute age. Note: no need for exact months.
Help TT

textbox disable in knockout

I have a table like below:
<tbody data-bind="foreach: tasks">
<tr>
<td>
<span data-bind="text: goal" />
</td>
<td>
<input type="text" data-bind="value: note ,
disable: !($data.isAllowedForMember)" />
</td>
</tr>
</tbody>
I want to make note textbox disable when isAllowedForMember = false. But everytime its making note disable(wheather isAllowedForMember = true or false).
Here is my viewmodel
//viewmodel
function GoalSheetViewModel() {
self.tasks = ko.observableArray([]); //tasklist
self.note = ko.observable();
self.isAllowedForMember = ko.observable();
self.IsAllowedToChange = function () {
$.ajax({
success: function (results) {
self.isAllowedForMember(results.d);
},
})
};
};
You should unwrap observable if you use it in condition:
<input type="text" data-bind="value: note , disable: !$parent.isAllowedForMember()" />
The following article can help you to learn some useful things about knockout: http://www.knockmeout.net/2011/06/10-things-to-know-about-knockoutjs-on.html
EDIT:
isAllowedForMember is member of parent context so you should use $parent object to access it:
<input type="text" data-bind="value: note , disable: !$parent.isAllowedForMember()" />
As Artem said you need to unwrap the observable, but even better to use a computed with a name saying what the business rule means
like
this.readonlyMember = ko.computed(function() {
return this.isAllowedForMember();
}, this);
But you also have a releation problem with your model since you get
ReferenceError: isAllowedForMember is not defined