how to generate different html if the given object has no results - javascript

I am talking to WP REST API and if I do have results in data object I generate HTML code to frontend, and that is working fine, but what to do, and how to generate different HTML output (for example "There is no search result") if there is not data in data object.
I try with if statement but no luck with that. I am new to coding so forgive me if this is trivial problem...
var searchVal = this.inputField.val();
$.getJSON('http://localhost:8888/wptest/wp-json/wp/v2/posts?search=' + searchVal,
data => {
this.createHtml.html(`
<h2 class="search-overlay__section-title">Posts Info</h2>
<ul class="link-list min-list">
<li>${data[0].title.rendered}</li>
</ul>
`);
});

Your code should work if its as below:
var searchVal = this.inputField.val();
$.getJSON('http://localhost:8888/wptest/wp-json/wp/v2/posts?search=' + searchVal,
data => {
if (data.length == 0) {
// no results html
} else {
this.createHtml.html(`
<h2 class="search-overlay__section-title">Posts Info</h2>
<ul class="link-list min-list">
<li>${data[0].title.rendered}</li>
</ul>
`);
}
});
Hope this helps !!

Hello guys I did a little research and found a more concise solution, Ternary Operator... sorry if I didn't say it was ES6 syntax and I used a compiler to run regular javascript in the browser
var searchVal = this.inputField.val();
$.getJSON('http://localhost:8888/wptest/wp-json/wp/v2/posts?search=' + searchVal,
data => {
this.createHtml.html(`
<h2 class="search-overlay__section-title">Posts Info</h2>
${data.length == 0 ? '<p>No Results</p>' : '<ul class="link-list min-list">'}
${data.map(item => `<li>${item.title.rendered}</li>`).join('')}
${data.length == 0 ? '</ul>' : ''}
`);
});

Related

Trouble hiding a div within a template literal using jQuery

I've written this bit of jQuery code in Oxygen Builder's JavaScript element to query the job board API and return an array of departments and their jobs. I'm testing to see if the department[0].jobs.length returns 0 then hide the #job-list div, otherwise show it and its associated jobs. The code succeeds in querying the API and returning 0 jobs but the remainder of the ternary operator will not hide the div.
jQuery(document).ready(function($) {
$.getJSON('https://boards-api.greenhouse.io/v1/boards/forwardnetworks/departments', postings => {
$("#div_block-420-61456").html(`
<div id="job-list">${postings.departments[0].jobs.length == 0 ? $("#job-list").hide() : $("#job-list").show()}<h3 class="dept">${postings.departments[0].name}</h3>
${postings.departments[0].jobs.map(item => `<h4 class="job-title">${item.title}</h4>
<p class="job-descrip">${item.location.name}`).join('')}</div> `);
});
});
I generally get a return of [object object]
As I mentioned in the comments, I would add a guard within the .getJSON success handler that will return early if there are no jobs to display.
The resulting function would be:
const departmentIndex = 0;
$(function ($) {
$.getJSON('https://boards-api.greenhouse.io/v1/boards/forwardnetworks/departments', postings => {
if (postings.departments[departmentIndex].jobs.length === 0) { return; }
$("#div_block-420-61456").html(`
<div id="job-list">
<h3 class="dept">${postings.departments[departmentIndex].name}</h3>
${postings.departments[departmentIndex].jobs.map(item => `
<a href="${item.absolute_url}">
<h4 class="job-title">${item.title}</h4>
</a>
<p class="job-descrip">${item.location.name}`
).join('')}
</div>
`);
});
});
Note: I put the index in a variable so that I could easily test with different departments.
Here is an example fiddle.

javascript, nested navbar from json

My aim is to replicate this structure automatically from a json file.
<ul class="sidebar-menu">
<li class="treeview">
Mammals
<ul class="treeview-menu">
<li>Goat</li>
<li> Sheep
<ul class="treeview-menu">
<li>Bone</li>
<li>Bone
<ul class="treeview-menu">
<li>Variant 1</li>
<li> Variant 2</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
JSON
[
{"datasetID":"5fd4124900827","higherClassification":"Eukarya","kingdom":"Animalia","phylum":"Chordata","class":"Mammalia","order":"Artiodactyla","family":"Bovidae","genus":"Capra","subgenus":"None","vernacularName":"goat","commonName":"None","elementName":"Calcaneus","commonElementName":"None"},
{"datasetID":"5fd4058e5c8d2","higherClassification":"Eukarya","kingdom":"Animalia","phylum":"Chordata","class":"Mammalia","order":"Artiodactyla","family":"Bovidae","genus":"Capra","subgenus":"None","vernacularName":"goat","commonName":"goat","elementName":"Femur","commonElementName":"None"}
]
The relevant parts are:
"datasetID":"5fd4124900827"
"class":"Mammalia",
"order":"Artiodactyla",
"family":"Bovidae",
"genus":"Capra",
"subgenus":"None",
"vernacularName":"goat",
"elementName":"Calcaneus"},
So the class is on the top level of the hierarchy, it could be mammal, bird, fish...
Taking class: Mammalia as an example, under this is order under that family under that genus
then if there is a subgenus that is on the next level also.
Under that is the vernacularName then elementName.
Each record has a unique id datasetID there may be multiple "elementName": "Calcaneus" for a goat, these need an integer added (i.e. Calcaneus 1, then Calcaneus 2, then Calcaneus 3 etc.
>Mammalia
>order
>family
>genus
>subgenus (if exists)
>vernacularName
>elementName (if more than one append 1,2,3...)
So, my mega question, how to do this in javascript?
My attempt so far:
Php gets the json, yes this could be done in javascript.
<?php
$data = json_decode(file_get_contents("bonify" . $version . "/app/json/data.json"), True);
?>
Javascript picks up the json:
<script type="text/javascript">
const version = "<?php echo $version; ?>";
$.getJSON('bonify'+ version +'/app/json/data2.json', function(json) {
console.log(json); // this will show the info it in firebug console
obj = json
This lists all the json data:
function printValues(obj) {
for(var k in obj) {
if(obj[k] instanceof Object) {
printValues(obj[k]);
} else {
document.write(obj[k] + "<br>");
};
}
};
closing code:
});
</script>
I'm not convinced document.write is the best way to do this.
I have this code for my search and it seems like I should adapt that but with out the filter capability.
$('#txt-search').keyup(function(){
var searchField = $(this).val();
if(searchField === '') {
$('#filter-records').html('');
return;
}
var regex = new RegExp(searchField, "i");
var output = '<div class="col-12 p-0"><hr />';
var count = 1;
$.each(data, function(key, val){
if ((val.datasetID.search(regex) != -1) || (val.ownerInstitutionCode.search(regex) != -1)|| (val.vernacularName.search(regex) != -1)|| (val.elementName.search(regex) != -1)) {
output += '<ul class="sidebar-menu">';
output += '<li><i class="fas fa-bone" data-fa-transform="rotate-45"></i> <span>' + val.vernacularName + ': ' + val.elementName + '</span></li>';
output += '</ul>';
if(count%2 == 0){
output += '</div>'
}
count++;
}
});
$('#filter-records').html(output);
});
});
});
I'm assuming several nested foreach loops is the way to go? I've put the whole aim for clarity. I am trying to learn and I have a learning disability so please be patient with me, thanks for your help. I've tried to included as much info as possible to avoid having my question closed as too broad.
You have a repeated pattern. If we assume that you have built a hierarchical data structure, then we can use a function using template literals, like:
function buildChildren(children) {
var tvms = [];
for (let child of children) {
tvms.push(myTreeViewMenu(child));
}
return tvms;
}
function myTreeViewMenu(treeViewMenu) {
tvms = buildChildren(treeViewMenu.children);
return `
<ul class="treeview-menu">
<li>${treeViewMenu.name} ${tvms.join("")}</li>
</ul>
`;
}
function myTree(tree) {
tvms = buildChildren(tree.children);
return `
<ul class="sidebar-menu">
<li class="treeview">
${tree.name}
${tvms.join("")}
</li>
</ul>
`;
}
(NOT TESTED)
This logic can be a starting point for you, basically you nest your pattern into itself. You need to make sure that from your raw JSON you build an object tree whose nodes have a string called name and an array for the subtree called children. Also, make sure there are no cycles in the tree.

Opening a div in a {{/if}} and closing it later with meteor/blaze

I'm trying to make something that is not possible in HTML/Blaze only.
By that I mean that I'm trying to open a div in a {{#if}} without closing it in this specific if. Impossible to do it the following way :
{{#each getData}}
{{#if equals this.level first}}
<div><p>content</p>
{{/if}}
{{#if equals this.level last}}
</div>
{{/if}}}
{{/each}}
So I found something that could solve this problem. Using triple curly braces and generate the HTML part in JS.
{{#each getData}}
{{{getContent this}}}
{{/each}}
getContent() return my HTML. It looks like this :
getContent(obj) {
if (obj.level == first)
return "<div><p>content</p>";
if (obj.level == last)
return "<p>content></div>";
else
return "<p>content</p>";
}
It works, it render the HTML, but there is one problem. The div I'm opening seems to close itself.
This is what's rendered :
<div><p>Content</p></div>
<p>content</p>
<p>content</p>
instead of :
<div><p>content</p>
<p>content</p>
<p>content</p>
</div
I'm really tired, I apologize if I'm not clear enough or if the solution is obvious.
EDIT: What I have now, and it's working fine, is the following :
HTML
{{#with getDataFromButton}}
{{formatData this}}
{{/with}}
JS
formatData(data) {
var res = "";
for (var i = 0; i < data.length; i++) {
if (data[i]["level"] == 0) {
if (res.length > 0)
res += "</div>";
res += "<div class=\"whiteBox\"><p>" + data[i]["value"] + "</p>";
}
else if ('last' in data[i]) {
res += "<p>" + data[i]["value"] + "</p></div>";
}
else {
res += "<p>" + data[i]["value"] + "</p>";
}
}
return res;
},
Thanks to all of you for the explanations ! And happy new year (it's not too late).
This is done because of browser try to fix HTML structure on any change. If you using Blaze, then HTML is rendered on the client side and in any evaluation of your helper code is injected to DOM. Then browser gets this HTML and tries to fix it.
Best solution is use simple pattern
<div>
{{#each getData}}
<p>content</p>
{{/each}}
</div>
If you want to apply the logic that you presented you have to prepare full correct HTML element in JS. You can to it as follow.
In template type: {{ myFullCorrectNodeElement }}
In JS type:
helpers: {
myFullCorrectNodeElement() {
let html = "";
const data = Template.instance().getData;
for(let i=0; i<data.length; i++) {
// your logic
if(i===0) {
html += `<div><p>content</p>`
// there you can access to variables by syntax ${}
// insde of ``, you can read about template strings from ES6
}
// ... and rest of your logic
}
return html;
}
}

Using array .map and $scope.__.reduce() for advanced angularjs filters

i'm currently building some advanced filters to use in a search input. I'm trying to search through multiple JSON objects at once. I've been able to use the functions .map and .reduce to create these filters. For more information look at this question that gave me this solution to work with. So for the orders page i've been able to add the customer firstname through this function. Take a look at the code below:
$http.get('config/get/getOrders.php', {cache: true}).then(function(response){
$scope.orders = response.data.orders.order;
$scope.orders.map( function addPlace(item) {
item.firstname = $scope.customers.reduce(function(a,customers){
return item.id_customer === customers.id ? customers.firstname : a;
}, '');
return item;
});
});
by using $scope.orders.map() and $scope.customers.reduce() i'm able to add a value to the orders array. By doing this i'm able to extend my search filter with the customer_name.
The problem i'm having now is actually two different things. The first thing is that i'm trying to create a more advanced comparison before obtaining one item. (The Combination_product_code) Take a look at the code below:
$http.get('config/get/getProducts.php', {cache: true}).then(function(response){
$scope.products = response.data.products.product;
$scope.products.map( function addPlace(item) {
item.eanCombination = $scope.productCombinations.reduce(function(a, productCombinations, stock_availables){
return item.id === stock_availables.id + stock_availables.id === stock_availables.id_product_attribute + stock_availables.id_product_attribute === productCombinations.id ? productCombinations.ean13: a;
}, '');
return item;
});
});
So as you can see i need to check through multiple values before i'm able to obtain the ean13 sadly this isn't working and i'm wondering if i'm setting the comparison right? i've checked all the value names multiple times and they are correct.
The second issue is adding multiple new items. I've been trying to add a product_name but also the products reference code. Take a look at the code below:
$http.get('config/get/getStock.php', {cache: true}).then(function (response) {
$scope.stock_availables = response.data.stock_availables.stock_available;
$scope.stock_availables.map( function addPlace(item) {
item.product_name = $scope.products.reduce(function(a,products){
return item.id_product === products.id ? products.name.language : a;
},
item.product_reference = $scope.products.reduce(function(b,products) {
return item.id_product === products.id ? products.reference: b;
}));
return item;
});
});
So my issues are adding multiple comparison queries before obtaining and adding the item and adding multiple items.
Update:
I've solved my issue about the "adding multiple items." The mistake i've made was in closing the function correctly. A working example:
$http.get('config/get/getStock.php', {cache: true}).then(function (response) {
$scope.stock_availables = response.data.stock_availables.stock_available;
$scope.stock_availables.map( function addPlace(item) {
item.product_name = $scope.products.reduce(function(a,products){
return item.id_product === products.id ? products.name.language : a;
}),
item.product_reference = $scope.products.reduce(function(b,products) {
return item.id_product === products.id ? products.reference: b;
});
return item;
});
});
This means that i'm looking for a solution about using multiple comparison queries before obtaining the data.
The workflow for this data is:
i'm using ng-repeat="product in products" within the products data i'm creating a filter that corresponds to the following data:
Products table:
id,
Name,
price,
etc,
stock table:
id,
product_id,
quantity,
product_attribute_id,
Combinations table:
id -> "Corresponds with attribute_id from stock table",
combinationEAN -> "The value i'm trying to reach",
So the workflow is:
Stock table -> id_product from products table -> combination id -> attribute_id from stock table.
I'm able to filter this within my view by using:
<h5 ng-if="combination.id >= 1 && product.id == stock_available.id_product && stock_available.id_product_attribute == combination.id" ng-repeat="combination in productCombinations" ng-bind="combination.ean13"></h5>
What i would like to to do is add that combination.ean13 directly to the products $scope by using the example above. So that i'm able to use a search input to search for that value and only show those products. See the example below:
<input type="text" class="bc-f3f3f3 form-control no-border" ng-model="productSearch" ng-change="filterProduct(productSearch)" placeholder="{{ 'Zoek of scan producten' | translate }}">
<div ng-infinte-scroll="loadMore()" infinite-scroll-disabled='products.busy' infinite-scroll-distance='1' class="align-center tcolor-2a95cf text-center padding-t-25 padding-s-45 no-margin row">
<div class="productimg col-4" ng-repeat="product in products | orderBy: '-date_add' | filter: filterProduct(productSearch) | filter: {id_category_default: productCategory}">
<div class="out-of-stock" ng-if="product.id == stock_available.id_product && stock_available.quantity == 0 && stock_available.id_product_attribute == 0" ng-repeat="stock_available in stock_availables">
<div class="stock-circle"></div>
</div>
<div>
<img ng-value="{{reference}}" data-toggle="modal" data-target=".bd-example-modal-sm{{product.id}}" ng-value="{{ean13}}" alt="{{product.name.language}}" ng-src="{{settings.url}}/{{product.id_default_image}}-home_default/{{product.link_rewrite.language}}.jpg" err-src="{{settings.url}}//img/p/nl-default-home_default.jpg" class="img-responsive product-img"/>
<p ng-bind="product.name.language"></p>
<p ng-bind="product.eanCombination"></p>
</div>
</div>
</div>
// Controller:
$http.get('config/get/getProducts.php', {cache: true}).then(function(response){
$scope.products = response.data.products.product;
$scope.products.map( function addPlace(item) {
item.eanCombination = $scope.productCombinations.reduce(function(a, productCombinations, stock_availables){
return item.id === stock_availables.id_product + stock_availables.id_product === stock_availables.id_product_attribute + stock_availables.id_product_attribute === productCombinations.id ? productCombinations.ean13: a;
}, '');
return item;
});
});
$scope.filterProduct = function(productSearch) {
return (name.language = productSearch) || (ean13 = productSearch) || (reference = productSearch) || (eanCombination = productSearch);
};
If you have any questions please ask them in the comments below.
As always, thanks in advance!

Array is returning correct results. but shows undefined in HTML display

I am having an issue with a project I'm working on. I am using an API to return an array of platforms a video game is on. The array is returning the correct results, however I am having trouble displaying those values in my HTML. The result is just showing undefined.
// Renders platform information for each game
const renderPlatformInfo = function (platformResult) {
const gamePlatform = [];
for (let i = 0; i <= `${platformResult.length - 1}`; i++) {
let getPlatforms = gamePlatform.push(platformResult[i].name);
}
gamePlatform.forEach(function (platformItem) {
$('.platforms').append(`<li>${platformItem}</li>`)
});
console.log(gamePlatform);
};
// Renders game information for the searched game
const renderGameInfo = function (gameInfoResult) {
return `<div class="js-game-data row">
<h2 class="game-name col-12">${gameInfoResult.name}</h2>
<img src="${gameInfoResult.image.medium_url}" class="game-image col-4" alt="Box art for ${gameInfoResult.name}">
<ul class="platforms col-6">
<h3 class="col-12">Original release date:</h3>${gameInfoResult.original_release_date}
<h3>Platforms:</h3>
${renderPlatformInfo(gameInfoResult.platforms)}
</ul>
<p class="game-description col-6">${gameInfoResult.deck} <br> <br> <span class="game-details col-12"><b>For more details about the game: Click Here</b></span></p>
</div>
`;
}
renderPlatformInfo can't append children to a DOM element that doesn't exist yet. The UL it's trying to select isn't rendered at the time you're trying to append. Additionally, since renderPlatformInfo doesn't return anything, it will always evaluate to undefined inside a template literal. If you return an HTML string inside renderPlatformInfo, your code should work. Try something like:
let str = '';
gamePlatform.forEach(function(platformItem){
str += `<li>${platformItem}</li>`;
});
return str;
Should renderPlatformInfo return something. Are you missing the return there?

Categories

Resources