js grid and autocomplete - node.js

I am able to create a custom field with jsGrid and jquery autocomplete. All ajax CRUD calls are working for all other fields. The below code activates autocomplete and shows the available options in the input field as expected.
var tags = ["tag1", "tag2", "tag3"];
MyDescriptionField.prototype = new jsGrid.Field({
insertTemplate: function(value) {
return this._editPicker = $("<input>").autocomplete({source : tags});
},
editTemplate: function(value) {
return this._editPicker = $("<input>").autocomplete({source : tags});
},
........... (more code)
So far so good. However to actually capture the value so it can be inserted into the db, I also need to define insertValue and editValue.
The code below is NOT working
insertValue: function(){
return this._insertPicker = $("<input>").val();
},
...........(more code)
this one is not working eiter:
insertValue: function(){
return this._insertPicker.autocomplete({
select: function(event, ui) {
$("<input>").val(ui.item.value);
}
});
},
reference: jsGrid. http://js-grid.com/demos/
autocomplete: https://jqueryui.com/autocomplete/

Try this snippet:
$(function() {
var myTagField = function(config) {
jsGrid.Field.call(this, config);
};
myTagField.prototype = new jsGrid.Field({
sorter: function(tag1, tag2) {
return tag1.localeCompare(tag2);
},
itemTemplate: function(value) {
return value;
},
insertTemplate: function(value) {
return this._insertAuto = $("<input>").autocomplete({source : tags});
},
editTemplate: function(value) {
return this._editAuto = $("<input>").autocomplete({source : tags}).val(value);
},
insertValue: function() {
return this._insertAuto.val();
},
editValue: function() {
return this._editAuto.val();
}
});
jsGrid.fields.myTagField = myTagField;
$("#jsGrid").jsGrid({
width: "100%",
inserting: true,
editing: true,
sorting: true,
paging: true,
fields: [
{ name: "Name", type: "text" },
{ name: "Tag", type: "myTagField", width: 100, align: "center" },
{ type: "control", editButton: false, modeSwitchButton: false }
],
data: db.users
});
});
var tags = ["tag1", "tag2", "tag3"];
var db = {};
db.users = [
{
"Name": "Carson Kelley",
"Tag": ""
},
{
"Name": "Prescott Griffin",
"Tag": "tag1"
},
{
"Name": "Amir Saunders",
"Tag": "tag3"
},
{
"Name": "Derek Thornton",
"Tag": "tag2"
},
{
"Name": "Fletcher Romero",
"Tag": ""
}];
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script src="//rawgit.com/tabalinas/jsgrid/master/dist/jsgrid.min.js"></script>
<link href="//code.jquery.com/ui/1.11.2/themes/cupertino/jquery-ui.css" rel="stylesheet"/>
<link href="//rawgit.com/tabalinas/jsgrid/master/dist/jsgrid.min.css" rel="stylesheet"/>
<link href="//rawgit.com/tabalinas/jsgrid/master/dist/jsgrid-theme.css" rel="stylesheet"/>
<div id="jsGrid"></div>
or this codepen: https://codepen.io/beaver71/pen/rpaLEo

Thanks #beaver. Your pen helped my understand custom fields better. I extended it a bit to add filtering with autocomplete. https://codepen.io/obrienje/pen/aQKNry
$(function() {
var myTagField = function(config) {
jsGrid.Field.call(this, config);
};
myTagField.prototype = new jsGrid.Field({
autosearch: true,
sorter: function(tag1, tag2) {
return tag1.localeCompare(tag2);
},
itemTemplate: function(value) {
return '<span class="label label-primary">' + value + '</span>';
},
insertTemplate: function(value) {
return this._insertAuto = $("<input>").autocomplete({
source: tags
});
},
filterTemplate: function(value) {
if (!this.filtering)
return "";
var grid = this._grid,
$result = this._filterAuto = $("<input>").autocomplete({
source: tags
});
if (this.autosearch) {
$result.on("change", function(e) {
grid.search();
});
}
return $result;
},
editTemplate: function(value) {
return this._editAuto = $("<input>").autocomplete({
source: tags
}).val(value);
},
insertValue: function() {
return this._insertAuto.val();
},
filterValue: function() {
return this._filterAuto.val();
},
editValue: function() {
return this._editAuto.val();
}
});
jsGrid.fields.myTagField = myTagField;
$("#jsGrid").jsGrid({
width: "100%",
filtering: true,
inserting: true,
editing: true,
sorting: true,
paging: true,
fields: [{
name: "Name",
type: "text"
},
{
name: "Tag",
type: "myTagField",
width: 100,
align: "center"
},
{
type: "control",
editButton: false,
modeSwitchButton: false
}
],
data: db.users,
controller: {
loadData: function(filter) {
return $.grep(db.users, function(item) {
return (!filter.Tag || item.Tag.toLowerCase().indexOf(filter.Tag.toLowerCase()) > -1);
});
}
}
});
});
var tags = ["tag1", "tag2", "tag3"];
var db = {};
db.users = [{
"Name": "Carson Kelley",
"Tag": ""
},
{
"Name": "Prescott Griffin",
"Tag": "tag1"
},
{
"Name": "Amir Saunders",
"Tag": "tag3"
},
{
"Name": "Derek Thornton",
"Tag": "tag2"
},
{
"Name": "Fletcher Romero",
"Tag": ""
}
];
<html>
<head>
<link href="https://rawgit.com/tabalinas/jsgrid/master/dist/jsgrid.min.css" rel="stylesheet"/>
<link href="https://rawgit.com/tabalinas/jsgrid/master/dist/jsgrid-theme.css" rel="stylesheet"/>
<link href="//code.jquery.com/ui/1.11.2/themes/cupertino/jquery-ui.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"/>
</head>
<body>
<h1>Custom Grid DateField filtering with autocomplete</h1>
<div id="jsGrid"></div>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script src="https://rawgit.com/tabalinas/jsgrid/master/dist/jsgrid.min.js"></script>
</body>
</html>
Thanks #beaver. Your pen helped my understand custom fields better. I extended it a bit to add filtering with autocomplete. https://codepen.io/obrienje/pen/aQKNry

Related

Laravel - Datatables export excel from filtered data

Hello i would like to export data from my datatable based on user filtered data here for example :
I have done export excel for all row but now i'm trying to export data based on filtered, here is my filtered function() in index.blade php:
$(".filterButton").on('click', function(){
tableMediaOrder.column(8).search($('.input-advertiser-filter').val()).draw();
tableMediaOrder.column(7).search($('.input-agency-filter').val()).draw();
tableMediaOrder.column(9).search($('.input-brand-filter').val()).draw();
});
i have tried to use formated Datatables example from Datatable example : Format Output Data, but i don't know how to put the export button and make it as a custom <a href=""> for the Excel export in image above, maybe someone can provide an example how to make it? thank you!.
EDIT :
here what is my input in index.blade.php :
<div class="col">
<button id="filterButton" class="btn btn-primary filterButton"><i class="fa fa-filter"></i> Filter</button>
<div class="dropdown d-inline">
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-file-excel-o"></i> Export
</button>
<!-- dropdown-menu -->
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" id="export-choose">
<a class="dropdown-item export-link" id="export-filtered">Excel</a>
<a class="dropdown-item export-link" href="{{ route('media-order.export') }}" id="exportRaw">Excel Raw</a>
</div>
<!-- end dropdown-menu -->
<button class="btn btn-primary float-right" data-toggle="modal" data-target="#addMediaOrderModal" data-backdrop="static" data-keyboard="false" class="btn btn-primary">
<i class="fa fa-plus-square mr-1"></i> Add Order
</button>
</div><!-- dropdown -->
</div>
So far i've been trying to put the <a href="" id="export-filtered"> to act as an Export button, add it as an onClick="exportFiltered" function and throw it into the javascript but it doesn't work, here is my javascript :
$(".exportFiltered").on('click', function(e) {
$('.hiddenbuttons button').eq(0).click();
});
but sadly it doesn't work, and it just make the Excel export become blank
UPDATE : Data Table
here is my datatable :
'use strict';
var addMediaOrderSubmitButton = Ladda('#addMediaOrderSubmitButton');
var editMediaOrderSubmitButton = Ladda('#editMediaOrderSubmitButton');
var tableMediaOrder = dt('#dt-media-order','media_order',{
// dom: '<"hiddenbuttons"B>rtip',
processing: true,
serverside: true,
iDisplayLength: 100,
bFilter: true,
searchable: true,
exportOptions: {
rows: 'visible'
},
ajax: {
url: "{{ route('media-order.index') }}?dt=1",
data: function (d){
d.filter_order = $('#input-order-filter').val();
d.filter_agency = $('#input-agency-filter').val();
d.filter_advertiser = $('#input-advertiser-filter').val();
d.filter_brand = $('#input-brand-filter').val();
// d.filter_start = $('#input-start-date').val();
// d.filter_end = $('#input-end-date').val();
//d.filterButton = $('#filterButton').val();
},
},
columns: [
{
data: 'action',
name: 'action',
orderable: false,
sortable: false,
className: 'text-center'},
{data: 'nomor', name: 'nomor'},
{data: 'nomor_reference', name: 'nomor_reference'},
{data: 'periode_start',
name: 'periode_start',
render: function(data){
var date = new Date(data);
var month = date.getMonth() + 1;
return (month.toString().length > 1 ? month : "0" + month) + "/" + date.getDate() + "/" + date.getFullYear();
}
},
{
searchable: true,
data: 'periode_end',
name: 'periode_end',
render: function(date){
var date = new Date(date);
var month = date.getMonth() + 1;
return (month.toString().length > 1 ? month : "0" + month) + "/" + date.getDate() + "/" + date.getFullYear();
}
},
{
searchable: true,
data: 'category_id',
name: 'category_id',
render: function(data, type, row) {
switch (data) {
case '1':
return 'New Order';
break;
case '2':
return 'Additional Order';
break;
case '3':
return 'Cancel Order';
break;
case '4':
return 'Paid';
break;
case '5':
return 'Bonus';
break;
default:
return 'Null';
break;
}
}
},
{
searchable: true,
data: 'type_id',
name: 'type_id',
render: function(data, type, row) {
switch (data) {
case '1':
return 'Reguler';
break;
case '2':
return 'Reguler PIB';
break;
case '3':
return 'CPRP';
break;
case '4':
return 'Package';
break;
case '5':
return 'Sponsor';
break;
case '6':
return 'Blocking';
break;
default:
return 'Null';
break;
}
}
},
{
searchable: true,
data: 'agency_name',
name: 'agency_name'
},
{
searchable: true,
data: 'advertiser_name',
name: 'advertiser_name'
},
{
searchable: true,
data: 'brand_name',
name: 'brand_name'
},
{
searchable: true,
data: 'version_code',
name: 'version_code'
},
{
data: 'gross_value',
name: 'gross_value' ,
render: $.fn.dataTable.render.number( ',', '.', 2, 'Rp','' )
},
{
data: 'nett_budget',
name: 'nett_budget',
render: $.fn.dataTable.render.number( ',', '.', 2, 'Rp','' )
},
{
data: 'nett_cashback',
name: 'nett_cashback',
render: $.fn.dataTable.render.number( ',', '.', 2, 'Rp','' )
},
{
data: 'nett_bundling',
name: 'nett_bundling',
render: $.fn.dataTable.render.number( ',', '.', 2, 'Rp','' )
},
{data: 'spot', name: 'spot' },
{
searchable: true,
data: 'accountexecutive_name',
name: 'accountexecutive_name'
},
{
searchable: true,
data: 'userto_name',
name: 'userto_name'
},
{
searchable: true,
data: 'group_id',
name: 'group_id'
},
{data: 'notes', name: 'notes' },
{
searchable: true,
data: 'attachment_name',
name: 'attachment_name'
}
],
buttons: [
{ // this exports only filtered data
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'applied' }
}
},
{ // this exports all data regardless of filtering
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'none' }
}
}
],
initComplete: function(setting, json){
$('.hiddenbuttons').css('display','none');
},
rowCallback: function( row, data, index) {
if (data.isdisabled == 1){
$(row).css('background-color', 'rgba(255, 0, 0, 0.2)');
}
}
});
UPDATE 2 :
it turns out i forgot to add the :
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.3.1/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.3.1/js/buttons.html5.min.js"></script>
And also is there a way to customize the column since the "Action" column are also being exported like this :
But sadly the custom export <a href="" id="export-filtered"> is still not working, thanks again.
UPDATE 3 :
After searching and tinkering, i've finally found my solution which is using :
var buttons = new $.fn.dataTable.Buttons(tableMediaOrder, {
buttons: [
{
extend: 'excelHtml5',
// "dom": {
// "button": {
// "tag": "button",
// "className" : "exportFiltered",
// }
// },
exportOptions: {
// rows: '"visible'
columns: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
modifier: { search: 'applied' }
}
}
]
}).container().appendTo($('#exportFiltered'));
And finally able to use the :
as a external link to export the excel.
You can delegate a DataTables export button to another external (non-DataTables) element.
The following example uses two different Excel Export buttons - one for a full export of all data, regardless of any filtering which has been applied, and the other to export only the filtered-in data:
buttons: [
// see https://datatables.net/reference/type/selector-modifier
{ // this exports only filtered data
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'applied' }
}
},
{ // this exports all data regardless of filtering
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'none' }
}
}
]
Then, we hide these buttons using the following:
dom: '<"hiddenbuttons"B>rtip'
and:
initComplete: function(settings, json) {
$('.hiddenbuttons').css('display', 'none');
}
These two DataTables export buttons can now be invoked from elsewhere - for example, based on the change event of a select list.
Here is the select list:
<select name="export" id="export">
<option value="noexport">-- select --</option>
<option value="filtered">Excel Filtered Data</option>
<option value="alldata">Excel All Data</option>
</select>
And here is the related event listener:
$("#export").on('change', function(e) {
var mode = $("#export :selected").val();
if (mode === 'filtered') {
$('.hiddenbuttons button').eq(0).click();
} else if (mode === 'alldata') {
$('.hiddenbuttons button').eq(1).click();
}
});
For reference, here is the full approach, as a self-contained web page:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.6.5/css/buttons.dataTables.min.css"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.6.5/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.6.5/js/buttons.html5.min.js"></script>
</head>
<body>
<div style="margin: 20px;">
<input type="text" id="name" placeholder="Enter name">
<input type="text" id="office" placeholder="Enter office">
<button id="filterButton" type="button">Filter</button>
<select name="export" id="export">
<option value="noexport">-- select --</option>
<option value="filtered">Excel Filtered Data</option>
<option value="alldata">Excel All Data</option>
</select>
<table id="example" class="display dataTable cell-border" style="width:100%">
</table>
</div>
<script>
var dataSet = [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": "2011/04/25",
"office": "Zurich",
"extn": "5421"
},
{
"id": "2",
"name": "Garrett Winters",
"position": "Accountant",
"salary": "$170,750",
"start_date": "2011/07/25",
"office": "Tokyo",
"extn": "8422"
},
{
"id": "3",
"name": "Ashton Cox",
"position": "Junior Technical Author",
"salary": "$86,000",
"start_date": "2009/01/12",
"office": "San Francisco",
"extn": "1562"
},
{
"id": "4",
"name": "Cedric Kelly",
"position": "Senior Javascript Developer",
"salary": "$433,060",
"start_date": "2012/03/29",
"office": "Edinburgh",
"extn": "6224"
},
{
"id": "5",
"name": "Airi Satou",
"position": "Accountant",
"salary": "$162,700",
"start_date": "2008/11/28",
"office": "Tokyo",
"extn": "5407"
},
{
"id": "6",
"name": "Donna Snider",
"position": "Customer Support",
"salary": "$112,000",
"start_date": "2011/01/25",
"office": "New York",
"extn": "4226"
}
];
$(document).ready(function() {
var table = $('#example').DataTable( {
dom: '<"hiddenbuttons"B>rtip',
lengthMenu: [ [5, -1], [5, "All"] ],
data: dataSet,
columns: [
{ title: "ID", data: "id" },
{ title: "Name", data: "name" },
{ title: "Office", data: "office" },
{ title: "Position", data: "position" },
{ title: "Start date", data: "start_date" },
{ title: "Extn.", data: "extn" },
{ title: "Salary", data: "salary" }
],
buttons: [
// see https://datatables.net/reference/type/selector-modifier
{ // this exports only filtered data
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'applied' }
}
},
{ // this exports all data regardless of filtering
extend: 'excelHtml5',
exportOptions: {
modifier: { search: 'none' }
}
}
],
initComplete: function(settings, json) {
$('.hiddenbuttons').css('display', 'none');
}
} );
$("#filterButton").on('click', function() {
table.column(1).search($('#name').val()).draw();
table.column(2).search($('#office').val()).draw();
});
$("#export").on('change', function(e) {
var mode = $("#export :selected").val();
if (mode === 'filtered') {
$('.hiddenbuttons button').eq(0).click();
} else if (mode === 'alldata') {
$('.hiddenbuttons button').eq(1).click();
}
});
} );
</script>
</body>
</html>
Update
If you want to use a <a> link to generate an Excel export, then maybe this will help:
Let's assume we have a link like the one from your question:
Excel
To handle a click event for this, you can use the following:
$("#export-filtered").on('click', function(e) {
e.preventDefault();
$('.hiddenbuttons button').eq(0).click();
});
Note that the link's ID is export-filtered - therefore you need to refer to that in your JavaScript, using the # symbol (which is for an ID) - and not the . symbol (which is for a class name):
$("#export-filtered")
Then you need to prevent the default click action from being applied, because you do not want the click to cause you to navigate to another page. I recommend doing this even if you have href="".
That works for me, using my DataTables code.
In your question, you do not show how you changed your DataTables code - so this may still not work for you. If that is the case, then there must be other differences (which are not shown in the question) between my example and your overall solution.

How do I create a multi-select header filter in tabulator?

This question has been asked several times in various forms over the years in the Tabulator GitHub repository. Here are a few instances:
https://github.com/olifolkerd/tabulator/issues/527, https://github.com/olifolkerd/tabulator/issues/1759
I'm looking for an example of how to achieve this using a dropdown menu of some form --- ideally as described in #1759 (dropdown with checkboxes) but another solution that would work for us is a "select" editor that adds/removes CSVs in the header filter when a value is selected/deselected (extending on the example provided in #527).
Hopefully someone with experience working with custom header filters / editors in tabulator can provide an example of a multi-select header filter dropdown, but if not, then I will post a JSFiddle link myself once I've got something that works.
Checkout: https://github.com/olifolkerd/tabulator/issues/527#issuecomment-850900451
Simple Answer by AkshayaBrianTauro
{
field: "book_name",
title: "Book Name",
headerFilterPlaceholder: " ",
headerFilter: 'select',
headerFilterFunc:"in",
headerFilterParams: {values:true, sortValuesList:"asc", multiselect:true}
},
Here is an example of a custom header filter for tabulator of 'select multiple' type. It can be converted to a dropdown style if desired using external sources such as Chosen or multiselect.js
(I recommend running the below Code Snippet in Full Page view).
const speciesTypes = ['Human', 'Android', 'Betazoid', 'Klingon', 'Ferengi', 'Tamarian'];
function multiSelectHeaderFilter(cell) {
var values = speciesTypes;
const filterFunc = (rowData) => {
return values.includes(rowData['species']);
}
const getSelectedValues = (multiSelect) => {
var result = [];
var options = multiSelect && multiSelect.options;
var opt;
for (var i = 0, iLen = options.length; i < iLen; i++) {
opt = options[i];
if (opt.selected) {
result.push(opt.value || opt.text);
}
}
return result;
}
const onChange = () => {
var editor = document.getElementById('speciesSelector');
values = getSelectedValues(editor);
console.log("values: " + values);
cell.getColumn().getTable().removeFilter(filterFunc);
cell.getColumn().getTable().addFilter(filterFunc);
}
var select = document.createElement("select");
select.multiple = "multiple";
select.id = 'speciesSelector';
select.class = "chosen-select";
select.style = 'width: 100%';
speciesTypes.forEach(species => {
select.innerHTML += "<option id='" + species + "' value='" + species + "' selected='selected'>" + species + "</option>";
});
cell.getColumn().getTable().addFilter(filterFunc);
select.addEventListener('change', onChange);
return select;
}
var table = new Tabulator("#tabulator", {
layout: "fitColumns",
data: [{
name: 'Geordi La Forge',
species: 'Human'
}, {
name: 'Dathon',
species: 'Tamarian'
}, {
name: 'Jean-Luc Picard',
species: 'Human'
}, {
name: 'Worf, son of Mogh',
species: 'Klingon'
}, {
name: 'Tasha Yarr',
species: 'Human'
}, {
name: 'Data',
species: 'Android'
}, {
name: 'Wesley Crusher',
species: 'Human'
}, {
name: 'Jalad',
species: 'Tamarian'
}, {
name: 'Lwaxana Troi',
species: 'Betazoid'
}, {
name: 'Temba',
species: 'Tamarian'
}, {
name: 'T\'Kuvma',
species: 'Klingon'
}, {
name: 'Lore',
species: 'Android'
}, {
name: 'Noonian Soongh',
species: 'Human'
}, {
name: 'Darmok',
species: 'Tamarian'
}, {
name: 'Reittan Grax',
species: 'Betazoid'
}, {
name: 'Quark',
species: 'Ferengi'
}],
headerSort: true,
columns: [{
title: 'Name',
field: 'name',
sorter: 'string'
}, {
title: 'Species',
field: 'species',
sorter: 'string',
headerFilter: multiSelectHeaderFilter,
headerFilterLiveFilter: false
}, ],
});
<html>
<head>
<link href="https://unpkg.com/tabulator-tables#4.5.3/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#4.5.3/dist/js/tabulator.min.js"></script>
</head>
<body>
<div id="tabulator"></div>
</body>
</html>
JSFiddle: https://jsfiddle.net/jjech/3th28pv0/
See my answer to Tabulator Multiple Filter in the same Column (show dropbox)
Extend as you see fit...
I dont think <select> support checkboxes as <option>'s, but it would be trivial to replace the <select> with a different style of "pulldown" that does.

how to iterate over objects of objects and display in mustache template

I have the following data structure
{ 'the-subtle-art-of-not-givng-a-f': { "id: "test", "title": "test"}, "the-hamset": {"id": "test", "title": "test"}}
how can I display the title in a mustache template?
jQuery
HTML:
<div id="output">
</div>
<script type="text/template" id="titles">
<ul>
{{#titles}}
<li>{{title}}</li>
{{/titles}}
</ul>
</script>
JS:
$(document).ready(function(){
const template = $('#titles').html();
const output = $('#output');
const object = {
'the-subtle-art-of-not-givng-a-f': {
"id": "test", "title": "test1"
},
"the-hamset": {
"id": "test", "title": "test2"
}
};
let titles = [];
for (const property in object) {
if (object.hasOwnProperty(property)) {
if (object[property].title) {
titles.push( { title: object[property].title });
}
}
}
const data = { titles };
const result = Mustache.render(template, data);
output.append(result);
});
Example
Vanilla JS:
HTML:
<div id="output">
</div>
<script type="text/template" id="titles">
<ul>
{{#titles}}
<li>{{title}}</li>
{{/titles}}
</ul>
</script>
JS:
const callback = function() {
const template = document.querySelector('#titles').innerHTML;
const output = document.querySelector('#output');
const object = {
'the-subtle-art-of-not-givng-a-f': {
"id": "test", "title": "test1"
},
"the-hamset": {
"id": "test", "title": "test2"
}
};
let titles = [];
for (const property in object) {
if (object.hasOwnProperty(property)) {
if (object[property].title) {
titles.push( { title: object[property].title });
}
}
}
const data = { titles };
const result = Mustache.render(template, data);
output.innerHTML = output.innerHTML + result;
};
if (
document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
callback();
} else {
document.addEventListener("DOMContentLoaded", callback);
}
Example

Can't call a nested key in Mongoose and Express (undefined)

I have a Mongoose Schema that display results. I can display the result array but not what's inside.
{
"_id": {
"$oid": "5cfa15e123d2f414da760635"
},
"objectID": 21078,
"cars_getroute": "volvo-123-gt-coach-1967-1968",
"gm_url": "https://www.url.com",
"results": [
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1967",
"price_str": "£4 982",
"price_int": 4982,
"price_currency": "£",
"sold": true,
"auction_house": "Anglia Car Auctions",
"auction_country": "Grande-Bretagne",
"auction_date": "25 août 2018",
"auction_datetime": "2018-08-25",
"auction_url": null,
"image_urls": null,
"price_int_eu": 5523
},
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1968",
"price_str": "CHF9 000",
"price_int": 9000,
"price_currency": "CHF",
"sold": true,
"auction_house": "Oldtimer Galerie",
"auction_country": "Suisse",
"auction_date": "29 avril 2017",
"auction_datetime": "2017-04-29",
"auction_url": null,
"image_urls": "https://www.url.com/img/auctions/car/thumb/17-4-11-f8a85a227775570cdeb80ba0a437cc40.jpg",
"price_int_eu": 8309
},
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1968",
"price_str": "Estimate £6 000 - £7 000 (unsold)",
"price_int": null,
"price_currency": null,
"sold": false,
"auction_house": "Herefordshire Vintage Auctions",
"auction_country": "Grande-Bretagne",
"auction_date": "20 octobre 2016",
"auction_datetime": "2016-10-20",
"auction_url": "http://www.url.com/Motor_details.php?pid=188&motor=188_01.jpg",
"image_urls": "https://www.url.com/img/auctions/car/2016-10-4a5a09eeb5c685e053e421c45656dcf7.jpg",
"price_int_eu": null
}
]
}
And the model:
const DemocarauctionSchema = new Schema({
objectID: {
type: Number
},
cars_getroute: {
type: String
},
gm_url: {
type: String
},
"results": { type: [{
marque: {
type: String
},
model: {
type: String
},
model_year: {
type: String
},
price_str: {
type: String
},
prince_int: {
type: Number
},
price_currency: {
type: String
},
sold: {
type: Boolean
},
auction_house: {
type: String
},
auction_country: {
type: String
},
auction_date: {
type: String
},
auction_datetime: {
type: String
},
auction_url: {
type: String
},
image_urls: {
type: String
},
price_int_eu: {
type: Number
},
}]}
},
{
collection: 'democarficheauction'
});
And when I call console.log(democarauctions.results.marque), nothing appears.
Is it a problem with my Schema ? Because There are multiple "marque" keys in the "results" array ?
It's working well with gm_url, objectId and cars_getroute.
EDIT: here is my Express route:
router.get('/demo/:cars_getroute', (req, res, next) => {
Promise.all([Democar.findOne({ cars_getroute: req.params.cars_getroute }), Democarauction.findOne({ cars_getroute: req.params.cars_getroute })])
.then(result => {
const [democars, democarauctions] = result;
console.log(democarauctions.results.marque)
res.render('demo/fichecar-demo', {
marque: democars.marque,
modele: democars.modele,
sous_modele: democars.sous_modele,
sous_modele2: democars.sous_modele2,
type: democars.type,
precision: democars.precision,
years_interval: democars.years_interval,
cote_actual: democars.cote_actual.toLocaleString('fr-FR'),
img_url: democars.img_url,
cote_1989_eu_excp: democars.cote.cote_1989.cote_1989_eu.cote_1989_excp,
cote_1989_eu_concours: democars.cote.cote_1989.cote_1989_eu.cote_1989_concours,
cote_1989_eu_base: democars.cote.cote_1989.cote_1989_eu.cote_1989_base,
cote_1989_eu_be: democars.cote.cote_1989.cote_1989_eu.cote_1989_be,
cote_1989_eu_me: democars.cote.cote_1989.cote_1989_eu.cote_1989_me,
cote_1989_eu_ar: democars.cote.cote_1989.cote_1989_eu.cote_1989_ar,
cote_1989_eu_epa: democars.cote.cote_1989.cote_1989_eu.cote_1989_epa,
cote_2004_excp: democars.cote.cote_2004.cote_2004_excp,
cote_2004_concours: democars.cote.cote_2004.cote_2004_concours,
cote_2004_base: democars.cote.cote_2004.cote_2004_base,
cote_2004_be: democars.cote.cote_2004.cote_2004_be,
cote_2004_me: democars.cote.cote_2004.cote_2004_me,
cote_2004_ar: democars.cote.cote_2004.cote_2004_ar,
cote_2004_epa: democars.cote.cote_2004.cote_2004_epa,
cote_2014_excp: democars.cote.cote_2014.cote_2014_excp,
cote_2014_concours: democars.cote.cote_2014.cote_2014_concours,
cote_2014_base: democars.cote.cote_2014.cote_2014_base,
cote_2014_be: democars.cote.cote_2014.cote_2014_be,
cote_2014_me: democars.cote.cote_2014.cote_2014_me,
cote_2014_ar: democars.cote.cote_2014.cote_2014_ar,
cote_2014_epa: democars.cote.cote_2014.cote_2014_epa,
cote_2017_excp: democars.cote.cote_2017.cote_2017_excp,
cote_2017_concours: democars.cote.cote_2017.cote_2017_concours,
cote_2017_base: democars.cote.cote_2017.cote_2017_base,
cote_2017_be: democars.cote.cote_2017.cote_2017_be,
cote_2017_me: democars.cote.cote_2017.cote_2017_me,
cote_2017_ar: democars.cote.cote_2017.cote_2017_ar,
cote_2017_epa: democars.cote.cote_2017.cote_2017_epa,
cote_2019_excp: democars.cote.cote_2019.cote_2019_excp,
cote_2019_concours: democars.cote.cote_2019.cote_2019_concours,
cote_2019_base: democars.cote.cote_2019.cote_2019_base,
cote_2019_be: democars.cote.cote_2019.cote_2019_be,
cote_2019_me: democars.cote.cote_2019.cote_2019_me,
cote_2019_ar: democars.cote.cote_2019.cote_2019_ar,
cote_2019_epa: democars.cote.cote_2019.cote_2019_epa,
cote_actual_chart: democars.cote_actual,
cote_actual_excp: democars.cote.cote_2019.cote_2019_excp.toLocaleString('fr-FR'),
cote_actual_concours: democars.cote.cote_2019.cote_2019_concours.toLocaleString('fr-FR'),
cote_actual_base: democars.cote.cote_2019.cote_2019_base.toLocaleString('fr-FR'),
cote_actual_be: democars.cote.cote_2019.cote_2019_be.toLocaleString('fr-FR'),
cote_actual_me: democars.cote.cote_2019.cote_2019_me.toLocaleString('fr-FR'),
cote_actual_ar: democars.cote.cote_2019.cote_2019_ar.toLocaleString('fr-FR'),
cote_actual_epa: democars.cote.cote_2019.cote_2019_epa.toLocaleString('fr-FR'),
perfo_1989: democars.performance.perfo1989,
perfo_2004: democars.performance.perfo2004,
perfo_2014: democars.performance.perfo2014,
perfo_2017: democars.performance.perfo2017,
results: democarauctions.results,
marqueauction: democarauctions.results.marque
}
});
})
.catch(err => {
// handle error.
console.log(err);
})
});
Here is my HTML template:
<div class="results__container--content">
{{#each results}}
<div class="results__container--box">
<h1>{{marqueauction}}</h1>
</div>
{{else}}
<div class="results__container--box">
<p>Aucun résultat d'enchères n'est disponible pour ce modèle.</p>
</div>
{{/each}}
</div>
results is an array, you should loop over the array to get the value of marque
let marqueauction = [];
for(let i =0; i < democarauctions.results.length; i++) {
marqueauction.push(democarauctions.results[i].marque)
}
res.render('demo/fichecar-demo', {
marqueauction: marqueauction
});
You can now render the marque in your HTML by looping over the marqueauction.

Not Getting Search value in Sencha Touch using searchfield

I want to display predictive text in search field, value for predictive text which comes from server. Here is my code so far:
View:
Ext.define('MyApp.view.AutoSearch', {
extend: 'Ext.dataview.List',
alias : 'widget.mainPanel',
config: {
store : 'AutoSearchStore',
itemTpl: '<div class="myWord">'+
'<div>Word is --<b>{name}</b>--- after search!!!</div>' +
'</div>',
emptyText: '<div class="myWord">No Matching Words</div>',
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Search...',
itemId: 'searchBox'
}
]
}
]
}
});
Store:
Ext.define('MyApp.store.AutoSearchStore',{
extend: 'Ext.data.Store',
config:
{
model: 'MyApp.model.AutoSearchModel',
autoLoad:true,
id:'Contacts',
proxy:
{
type: 'ajax',
url: 'http://alucio.com.np/trunk/dev/sillydic/admin/api/word/categories/SDSILLYTOKEN/650773253e7f157a93c53d47a866204dedc7c363',
reader:
{
rootProperty:''
}
}
}
});
Model:
Ext.define('MyApp.model.AutoSearchModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.AutoSearchModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name: 'name'},
],
},
});
and
Ext.define('MyApp.model.AutoSearchModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
'name',
],
belongsTo: "MyApp.model.AutoSearchModel"
}
});
Controller:
Ext.define('MyApp.controller.SearchAutoComplete', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['MyApp.store.AutoSearchStore'],
models : ['MyApp.model.AutoSearchModel'],
refs: {
myContainer: 'mainPanel'
},
control: {
'mainPanel': {
activate: 'onActivate'
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
}
}
},
onActivate: function() {
console.log('Main container is active--Search');
},
onSearchKeyUp: function(searchField) {
queryString = searchField.getValue();
console.log(this,'Please search by: ' + queryString);
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
}
},
onClearSearch: function() {
console.log('Clear icon is tapped');
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
},
init: function() {
console.log('Controller initialized for SearchAutoComplete');
}
});
Json Data Looks Like:
"data":[
{
"name":"paint",
"author":"admin",
"word_id":"1",
"category":"Business",
"is_favourite":"yesStar"
},
{
"name":"abacus",
"author":"admin",
"word_id":"2",
"category":"Education",
"is_favourite":"yesStar"
},
{
"name":"abate",
"author":"admin",
"word_id":"3",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"testing adsf",
"author":"admin",
"word_id":"7",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"sprite",
"author":"admin",
"word_id":"6",
"category":"Business",
"is_favourite":"noStar"
},
{
"name":"newword",
"author":"admin",
"word_id":"8",
"category":"Architecture",
"is_favourite":"noStar"
}
]
})
If I type "A", then it displays No Matching Words, but I have words from "A" on json coming from server. How to solve this problem?
Any idea!
Code Sources Link
I don't know why you are using two models but just one thing you need to specify in AutoSearchStore :
reader:
{
rootProperty:'data'
}
instead of
reader:
{
rootProperty:''
}
to get the expected results in the list.
Hope this will be helpful :)

Resources