Angular2 Search Filter How to display No Record is found - angular2-template

<input Type="text" (keyup)="someval('$event.target.value')"/>
<table>
<tr>
<th> Id</th>
<th>Name</th></tr>
<tr *ngFor="let emp of pagedItems">
<td>{{emp.Id}}</td>
<td>{{emp.Name}}</td>
</tr>
<tr *ngIf="ErrorHandle">
<td colspan="5">
{{ErrorMsg}}
</td>
</tr>
Typescript
Here i writen some code to handle my Search text box its accepect Id value and find rec within the table.When Record is their its display the Rec but wen its not available i wana 2 hide *ngFor
someval(value){
if(value.length>=5){
this._pagedItems= this.allItems.find(e=>e.uniqueid == value);
if(this._pagedItems == undefined){
this.ErrorHandle=true;
this.ErrorMsg="No Such Record is Present......."
}
else{
this.pagedItems=[];
this.pagedItems.push(this._pagedItems);
}

You can do something like following code. I create it in FIDDLE
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular 6';
ErrorHandle :Boolean = false;
ErrorMsg :string ="No Such Record is Present.......";
allItems = [{ Id: 1, Name: "chintan" }]
pagedItems = [];
emp = { Id: 1, Name: "chintan" };
someval(value) {
if (value) {
this.pagedItems = [];
let emp = this.allItems.find(e => e.Id == value);
if (emp == undefined) {
this.ErrorHandle = true;
} else {
this.ErrorHandle = false;
this.pagedItems.push(emp);
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/2.0.0-beta.17/angular2-all-testing.umd.dev.js"></script>
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<input Type="text" (keyup)="someval($event.target.value)" />
<table>
<tr *ngIf="!ErrorHandle">
<th> Id</th>
<th>Name</th>
</tr>
<tr *ngFor="let emp of pagedItems">
<td>{{emp.Id}}</td>
<td>{{emp.Name}}</td>
</tr>
<tr *ngIf="ErrorHandle">
<td colspan="5">
{{ErrorMsg}}
</td>
</tr>
</table>

Related

display a foreign data in a table vuejs

I am creating a page, in which a section called product, I show data and in this I have a data called id_categoria, where instead of showing the id I want to show the name of that category in question, this data is in the table of categories and in the product table I have the id. I already managed to show the data, but not this, besides that I managed to save and edit it in question, it is only necessary in show.
When working with vuejs I saw that you have to use a v-if but I do not know how to do it, or at least the attempts I have made have been wrong.
this is the code of the table where I show the data
<div class="card-body table-responsive">
<table id="example1" class="table table-bordered table-striped">
<thead>
<tr>
<th>id_producto</th>
<th>imagen</th>
<th>código</th>
<th>producto</th>
<th>categoria</th>
<th>stock</th>
<th>precio_compra</th>
<th>precio_venta</th>
<th>fecha</th>
<th colspan="2" class="text-center">Acciones</th>
</tr>
</thead>
<tbody>
<tr v-for="pro in productos" :key="pro.id_productos">
<th>{{pro.id_productos}}</th>
<td>
<img :src="pro.imagen" class="img-circle elevation-2" alt="Product Image" width="60" />
</td>
<td>{{pro.codigo}}</td>
<td>{{pro.producto}}</td>
<td>{{pro.id_categoria}}</td>
<td>{{pro.stock}}</td>
<td>{{pro.precio_compra}}</td>
<td>{{pro.precio_venta}}</td>
<td>{{pro.fecha}}</td>
<td class="text-center">
<button #click="modificar=true; abrirModal(pro)" type="button" class="editar btn btn-primary"><i class="fa fa-pencil-alt"></i></button>
</td>
<td class="text-center">
<button #click="eliminar(pro.id_productos,pro.producto)" type="button" class="eliminar btn btn-danger" data-toggle="modal" data-target="#modalEliminar"><i class="fas fa-dumpster-fire"></i></button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>id_producto</th>
<th>imagen</th>
<th>código</th>
<th>producto</th>
<th>categoria</th>
<th>stock</th>
<th>precio_compra</th>
<th>precio_venta</th>
<th>fecha</th>
<th colspan="2" class="text-center">Acciones</th>
</tr>
</tfoot>
</table>
</div>
and this is the script to bring the info to me
<script>
import axios from "axios";
export default {
watch: {
$route: {
immediate: true,
handler(to, from) {
document.title = to.meta.title || 'Productos';
}
},
},
data() {
return{
productosdatos:{
id_producto: "",
codigo: "",
producto: "",
stock: "",
precio_compra: "",
precio_venta : "",
id_categoria: "",
},
id: 0,
modificar: true,
modal: 0,
tituloModal: '',
productos:[],
categorias:[],
}
},
methods: {
async listarcategorias(){
const res = await axios.get('http://localhost:8000/categoria/');
this.categorias = res.data;
console.log(this.categorias)
},
async listar(){
const res = await axios.get('http://localhost:8000/productos/');
this.productos = res.data;
console.log(this.productos)
},
cerrarModal(){
this.modal = 0;
}
},
created() {
this.listar();
}
}
</script>
as you can see I have a variable called products, where is the id_category corresponding to the product, and categories where I bring all the category info.
the table looks something like this:
how can I make it not show the id of the category but the name of the category in question ?
pd: the category data is received in json as follows:
{
"id_categoria": 8,
"categoria": "Electrodomesticos",
"fecha": "2021-10-24 13:55:00"
}
thank you if you can help me to show the name of the category thank you
You can implement a function like this:
const findCategory = (id)=>{this.categorias.find(category=>category.id_categoria===id)?.categoria}
And in the template:
<td>{{findCategory(pro.id_categoria)}}</td>
Only one small change. In your code you have to edit. pro.id_categoria to pro.categoria. see comment inline.
<tr v-for="pro in productos" :key="pro.id_productos">
<th>{{pro.id_productos}}</th>
<td>
<img :src="pro.imagen" class="img-circle elevation-2" alt="Product Image" width="60" />
</td>
<td>{{pro.codigo}}</td>
<td>{{pro.producto}}</td>
// this line
<td>{{pro.id_categoria}}</td>
// edit to
<td>{{ pro.categoria }} </td>

nested v-for loop not rendering

I am trying to display a table full of Orders and the corresponding Order details in a row-like fashion. However, I've run into a bit of a conundrum. Any geniuses out there? I've tried all sorts of variations in approaching this problem but I'm stuck. Someone mentioned that perhaps using a 'computed' property would do the trick but I haven't been able to get it to work >=/. A bit of help, maybe a lot of help, would be greatly appreciated!
<div id="MyOrdersApp" class="table-responsive">
<table class="table table-striped table-bordered table-condensed">
<thead>
<tr style="color:black;font-size:2em;">
<th style="text-align:center;">Order Id</th>
<th style="text-align:center;">ProductIdsAndQuantity</th>
<th style="text-align:center;">Total Cost</th>
<th style="text-align:center;">Order Status</th>
<th style="text-align:center;">Shipment Tracking URL</th>
<th style="text-align:center;">Created Date</th>
</tr>
</thead>
<tbody>
<tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" class="align-content-center;">
<td>{{order.OrderId}}</td>
<td>
<ul>
<li v-if="order.CartLineItems != null" v-for="item in order.CartLineItems;" :key="uniqueKey">
<img :src="item.ProductImageUrl" />
<span>{{item.ProductName}} | </span>
<span>Quantity: {{item.Quantity}} | </span>
</li>
</ul>
</td>
<td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
<td>{{order.OrderStatus}}</td>
<td>{{order.ShipmentTrackingURL}}</td>
<td>{{order.CreatedDate | formatDate }}</td>
</tr>
</tbody>
</table>
</div>
<script>
var MyOrdersApp = new Vue({
el: '#MyOrdersApp',
data: {
parsedOrders: [],
theOrders: [],
uniqueKey: 0
},
computed: {
cartLineItems: function () {
return this.parsedOrders[0].CartLineItems;
}
},
methods: {
getMyOrders: function () {
var scope = this;
this.$http.get("https://" + location.host + "/Home/GetMyOrders").then(resp => {
if (resp.status == 200) {
this.theOrders = resp.body;
scope.setCartLineItems();
}
});
},
setCartLineItems: function () {
var scope = this;
var cartLineItems = [];
var cartDict = {};
for (var i = 0; i < this.theOrders.length; i++) {
cartDict = {};
cartLineItems = [];
cartDict = JSON.parse(this.theOrders[i].ProductIdsAndQuantity).CartLineItems;
for (var key in cartDict) {
var lineItem = JSON.parse(cartDict[key]);
cartLineItems.push(lineItem);
}
//this.allorders[i].CartLineItems = cartLineItems;
//scope.$set(this.allorders[i], 'CartLineItems', cartLineItems);
//this.theOrders[i].CartLineItems = cartLineItems;
scope.$set(this.theOrders[i], 'CartLineItems', cartLineItems);
}
this.parsedOrders = this.theOrders;
console.log("~~ Parsed Cart! ~~ ");
console.log(this.parsedOrders);
console.log(this.parsedOrders[1].CartLineItems);
}
},
mounted: function () {
var scope = this;
this.getMyOrders();
setTimeout(x => { scope.$forceUpdate(); scope.uniqueKey++; }, 1000);
}
});
</script>
How should I modify this to properly display the values in 'CartLineItems'??
Btw, parsedOrders looks like this:
If I comment out the inner v-for, the other columns display just fine and the table looks like this:
Some more background... when I fetch the orders via the $http call and the server returns the array of JSON, the ProductIdsAndQuantity property needs to be parsed as a JSON object and then set as it's own property on the order in question. The tricky part here is that the Vue component seems to not be reacting to the change in the order object array data. Hence, the need for a parsedOrders property and/or the use of scope.$forceUpdate(); or scope.uniqueKey++;. These were proposed solutions to the issue of the Vue component not re-rendering. However, these solutions are not working. So I'm stuck scratching my head...
You can't have both v-for and v-if on the same statement that's what is causing the issue. So instead try using computed in this case
<tbody>
<tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" class="align-content-center;">
<td>{{order.OrderId}}</td>
<td>
<ul>
<li v-for="(item, index) in getCartLineItems(order)" :key="index">
<img :src="item.ProductImageUrl" />
<span>{{item.ProductName}} | </span>
<span>Quantity: {{item.Quantity}} | </span>
</li>
</ul>
</td>
<td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
<td>{{order.OrderStatus}}</td>
<td>{{order.ShipmentTrackingURL}}</td>
<td>{{order.CreatedDate | formatDate }}</td>
</tr>
</tbody>
and in computed
computed: {
getCartLineItems() {
return order => {
if(order?.CartLineItems && order.CartLineItems.length) return order.CartLineItems;
return [];
}
}
}

Trouble using renderRows in Mat-Table

I'm trying to update my table in angular 8, when data is added using renderRows() method but it is not working.
I have used #ViewChild and .renderRows() method after getting response also can anyone explain the meaning of this : {static: true}
//TODO: allocateMoney.ts
#ViewChild(MatTable, { static: true }) table: MatTable<any>;
openDialog() {
let dialogRef = this.dialog.open(AllocateMoneyFormComponent, {
disableClose: true,
data: {
projectId: this.projectId,
budgetId: this.budgetId
}
});
dialogRef.afterClosed().subscribe((result) => {
if (result == 'loadData') {
this.table.renderRows();
}});
}
//TODO: allocateMoney.html
<table class="example-list" mat-table [dataSource]="budget_dm.budget[budgetId].allocateMoney.tables.rows"
class="mat-elevation-z8">
<ng-container matColumnDef="id">
<th mat-header-cell [style.display]="'none'" *matHeaderCellDef> Id </th>
<td mat-cell [style.display]="'none'" *matCellDef="let element">{{element.id}}
</td>
</ng-container>
<ng-container matColumnDef="categoryCode">
<th mat-header-cell *matHeaderCellDef style="padding-left: 15px;"> Acc </th>
<td mat-cell *matCellDef="let element">{{element.categoryCode}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="budget_dm.budget[budgetId].allocateMoney.tables.cols"></tr>
<tr class="example-box" mat-row
*matRowDef="let row; columns: budget_dm.budget[budgetId].allocateMoney.tables.cols;"></tr>
</table>
//TODO: allocateMoneyForm.ts
isSubmitForm() {
this.formdata.raw.projectId = this.projectId;
this.formdata.raw.budgetId = this.budgetId;
this.budgetService.allocateMoney(this.orgId, this.formdata.raw).then(resp => {
if (resp) {
this.toast_.successToastr("Money Allocated Success", "SUCCESS");
} else {
this.toast_.errorToastr("Money Allocated Failure", "ERROR");
}
});
this.dialogRef.close('loadData');
}
core.js:5847 ERROR TypeError: Cannot read property 'renderRows' of undefined
at SafeSubscriber._next (allocate-money.component.ts:57)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:192)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (Subscriber.js:130)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53)
at Subject.push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next (Subject.js:47)
at SafeSubscriber._next (dialog.es5.js:429)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:192)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (Subscriber.js:130)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76)
Try adding the #table reference to your html mat table , this is to make sure your mat table childview is well instantiated

Bootstrap Select and dynamic rows issue in vue.js

I have the following dynamic table/rows in vue.js and I use bootstrap-select to have a nicer dropdown select. The form has a add/remove line to be dynamic. I cannot load the options of a select using bootstrap select. The select appears on each row but no dropdown list appears.
What am I doing wrong?
here goes my jsfiddle
HTML:
<div id="app">
<table class="table">
<thead>
<tr>
<td><strong>Date</strong></td>
<td><strong>Account</strong></td>
<td><strong>Debit</strong></td>
<td><strong>Credit</strong></td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="row in rows">
<td>
<input type="date" v-date="row.myDate">
</td>
<td>
<select class="selectpicker" ref="select" v-model="row.select">
<option value="Acc1">Account1</option>
<option value="Acc2">Account2</option>
<option value="Acc3">Account3</option>
<option value="Acc4" selected>Account4</option>
</select>
</td>
<td>
<input type="text" v-model="row.debit" v-on:keypress="isNumber(event)">
</td>
<td>
<input type="text" v-model="row.credit" v-on:keypress="isNumber(event)">
</td>
<td><a #click="removeRow(row)">Remove</a></td>
</tr>
</tbody>
<tfooter>
<td class="al-g"> <button class="button btn-primary" #click="addRow">Add Line</button></td>
<td></td>
<td class="al-r">tot D.: {{ totaldebit | roundme }}</td>
<td class="al-r">tot Cr.:{{ totalcredit | roundme}}</td>
<td class="al-r">Dif: {{ totaldebit-totalcredit | roundme}}</td>
</tfooter>
</table>
</div>
JS:
Vue.filter('roundme', function (value) {
return value.toFixed(3);
})
var app = new Vue({
el: "#app",
data: {
rows: [{debit:0, credit:0},
]
},
computed: {
totaldebit() {
return this.rows.reduce((total, row) => {
return total + Number(row.debit);
}, 0);
},
totalcredit() {
return this.rows.reduce((total, row) => {
return total + Number(row.credit);
}, 0);
}
},
methods: {
addRow: function() {
this.rows.push({myDate:"",
account:"",
debit: "",
credit: ""
});
},
removeRow: function(row) {
//console.log(row);
this.rows.$remove(row);
},
isNumber: function(evt) {
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if ((charCode > 31 && (charCode < 48 || charCode > 57)) && charCode !== 46) {
evt.preventDefault();;
} else {
return true;
}
}
}
});
You are going to need a wrapper component like this.
The way bootstrap-select normally activates is to scan the HTML at startup and apply itself to .selectpicker elements. That won't work if the DOM is dynamic, as it is with Vue. You have to activate the elements using the $(element).selectpicker() method as they are created or updated.
See also Make VueJS and jQuery play nice.

Can datatables sort a column with an input field?

I am trying to make datatables sort my columns. The first column works okay as it's a simple number. However the next column is an input field. When I try to make that sort then nothing happens.
<table width="100%" cellspacing="0" class="table sortable no-margin">
<thead>
<tr>
<th scope="col" class="sorting" style="width: 57px;">
<span class="column-sort">
</span>
ID
</th>
<th scope="col" class="sorting_desc" style="width: 94px;">
<span class="column-sort">
</span>
Order
</th>
</tr>
</thead>
<tbody>
<tr id="row_20" class="odd">
<td id="refKey_20" style="text-align:center;" class="">
1Y
</td>
<td class=" sorting_1">
<input type="text" value="160" size="3" name="item.Order"
maxlength="3" id="Order_20" >
</td>
</tr>
<tr id="row_19" class="even">
<td id="refKey_19" style="text-align:center;" class="">
1X
</td>
<td class=" sorting_1">
<input type="text" value="150" size="3" name="item.Order"
maxlength="3" id="Order_19" >
</td>
</tr>
</tbody>
</table>
Is there some way that I can get datatables to sort input fields?
The easiest way is to add a hidden span inside columns <span style="visibility:hidden">value of the input</span>
You should look at this example that explains how to do sorting on input fields. Basically you declare a sorting function
/* Create an array with the values of all the input boxes in a column */
$.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
{
var aData = [];
$( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
aData.push( this.value );
} );
return aData;
}
And then tell to your table to use that
$('#example').dataTable( {
"aoColumns": [
null,
{ "sSortDataType": "dom-text" }
]
} );
or wit aoColumnDefs
$('#example').dataTable( {
"aoColumnDefs": [{ "sSortDataType": "dom-text" , aTarget: "yourclass"}]
} );
For versions of Datatables 1.10+ the names of some option variables have been changed and a new API introduced. Documentation here: http://datatables.net/examples/plug-ins/dom_sort.html.
Here is a working version of the above accepted answer in 1.10+:
$(document).ready(function () {
var table = $('#example').DataTable({
"columnDefs": [
{
"orderDataType": "dom-input",
"targets": 0, // Just the first column
},
],
});
});
The custom sort function:
$.fn.dataTable.ext.order['dom-input'] = function (settings, col) {
return this.api().column(col, { order: 'index' }).nodes().map(function (td, i) {
return $('input', td).val();
});
}
jQuery.fn.dataTableExt.oSort['textbox-asc'] = function (a, b) {
var vala = $('#' + $(a).filter('input').attr('id')).val().toLowerCase();
var valb = $('#' + $(b).filter('input').attr('id')).val().toLowerCase();
if (vala === '')
return 1;
if (valb === '')
return -1;
return vala < valb ? -1 : vala > valb ? 1 : 0;
};
jQuery.fn.dataTableExt.oSort['textbox-desc'] = function (a, b) {
var vala = $('#' + $(a).filter('input').attr('id')).val().toLowerCase();
var valb = $('#' + $(b).filter('input').attr('id')).val().toLowerCase();
if (vala === '')
return 1;
if (valb === '')
return -1;
return vala < valb ? 1 : vala > valb ? -1 : 0;
};
then use it like this
$(datatable).dataTable({
"iDisplayLength": 50,
"bLengthChange": false,
"bPaginate": false,
"columns": [
null, { "sType": "textbox" }
],
});
If you decide to use the columns option where you are rending information from a JSON file you can easily add a hidden span on your render property. It appears as though DataTables looks for text to order and if it cannot find any, it will break. The example at https://datatables.net/examples/plug-ins/dom_sort.html uses a table that has already been rendered. Here is an example using an API:
...columns([{
"data": "receivedDate",
"render": function (data, type, row, meta)
{
if (data == "null")
{
return "<input type='text' id='datepicker_" + meta.row + "' class='datepicker form-control' /><span class='hidden'><span>";
}
else
{
return "<input type='text' id='datepicker_" + meta.row + "' class='datepicker form-control' value='" + moment(data).format("MM/DD/YYYY") + "'/><span class='hidden'>" + moment(data).format('MM/ DD / YYYY') + "</span>";
}
}
}]);
Set an invisible div with the value before the input field.
<tbody>
<tr id="row_20" class="odd">
<td id="refKey_20" style="text-align:center;" class="">
1Y
</td>
<td class=" sorting_1">
<div style="display:none;">160</div>
<input type="text" value="160" size="3" name="item.Order"
maxlength="3" id="Order_20" >
</td>
</tr>
<tr id="row_19" class="even">
<td id="refKey_19" style="text-align:center;" class="">
1X
</td>
<td class=" sorting_1">
<div style="display:none;">150</div>
<input type="text" value="150" size="3" name="item.Order"
maxlength="3" id="Order_19" >
</td>
</tr>
</tbody>