Is it a good idea to use images local URL in array? - javascript

I want to make a list of projects and I made an array and using .map() method to display them, and I'm adding that list in the HTML element using .insertAdjacentHTML() method.
While inspecting the elements I can see the image path is coming fine but image is not showing in UI. What would be the reason of it?
const projectData = [
{
id: 01,
title: "Project 1",
url: "https://react-projects-1/",
imageUrl: "src/img/projects/project-1.png", //is it wrong using like this
description: "This is project 1 desc",
},
{
id: 02,
title: "Project 2",
url: "https://react-projects-2/",
imageUrl: "src/img/projects/project-2.png", //is it wrong using like this
description: "This is project 2 desc",
},
];
Mapping them and using the HTML:-
const projectHTML = projectData.map((el) => {
return `<div class="row align-items-center project_row">
<div class="col-md-5 col-12 order-md-2">
<a href="${el.url}" class="thumb">
<img
src="${el.imageUrl}"
class="w-100"
alt="${el.title}"
target="_blank"
/>
</a>
</div>
<div class="col-md-7 col-12 order-md-1 mt-4 mt-md-0">
<h3><span>${el.id}.</span>${el.title}</h3>
<p>
${el.description}
</p>
<ul class="buildTech">
<li><i class="fa-brands fa-react"></i> React</li>
</ul>
View
</div>
</div>`;
});
workWrapper.insertAdjacentHTML("afterbegin", projectHTML);
Inspect:-

Related

Independent HTTP status for each array element

I am using the following code to print some information in HTML.
I have problems.
First, I use:
fetch(resultado.url).then(function(response) {console.log(response.status);
To obtain the http status of the URL that is inside the array "channelList", but I don't know how to get that state independently, I mean, for all elements of the array.
And after that, if I change 'getElementbyID' to 'getElementbyClassName' to show 'status' in HTML, this doesn't work
const channelList = [
{
name: "La 1",
title: "RTVE La 1",
link: "go:la1",
imgClass: "la1",
flag: "es",
url: "./la1.html",
},
{
name: "La 2",
title: "RTVE La 2",
link: "go:la1",
imgClass: "la1",
flag: "es",
url: "./la2.html",
},
];
const resultado = channelList.find( canal => canal.name === 'La 1' );
// HTTP STATUS
fetch(resultado.url).then(function(response) {
console.log(response.status);
if(response.status !== 200){
let stt = document.getElementById('hlstatus');
stt.innerText = "Offline";
} else {
document.getElementById('hlstatus').innerText = "Online";
}
});
// PRINT ON HTML
const container = document.getElementById("locales");
var img = "https://cdn.sstatic.net/Img/teams/teams-illo-free-sidebar-promo.svg?v=47faa659a05e";
channelList.forEach(result => {
// Construct card content
const content = `
<div class="col-6 col-sm-4 col-lg-3 col-xl-2">
<div class="dropdown card darkolorbg text-white card-canal card-link text-white">
<a class="card-link text-white" href="${result.link}" ${result.dDown}>
<div class="card-body">
<div class="d-flex justify-content-center">
<img class="canal-img ${result.imgClass}" src="${img}" alt="">
</div>
<div class="d-flex justify-content-center"><h5>${result.name} <span class="hidden">${result.title}</span> <br><span class="subtf1"><i class="flag ${result.flag}"></i></span> <span id="hlstatus"></span> </div>
</div>
</a>
</div>
</div>
`;
// Append newyly created card element to the container
container.innerHTML += content;
});
<div id="locales"></div>
If I understood you correctly, this code should work as you expect.
But pay attention, please, to error processing.
It could be done by passing callback function to .catch method of the promise.
var img = "https://cdn.sstatic.net/Img/teams/teams-illo-free-sidebar-promo.svg?v=47faa659a05e";
const container = document.getElementById("locales");
// PRINT ON HTML
function makeStatusCard(result) {
const content = `
<div class="col-6 col-sm-4 col-lg-3 col-xl-2">
${result.status}
<div class="dropdown card darkolorbg text-white card-canal card-link text-white">
<a class="card-link text-white" href="${result.link}" ${result.dDown}>
<div class="card-body">
<div class="d-flex justify-content-center">
<img class="canal-img ${result.imgClass}" src="${img}" alt="">
</div>
<div class="d-flex justify-content-center"><h5>${result.name} <span class="hidden">${result.title}</span> <br><span class="subtf1"><i class="flag ${result.flag}"></i></span> <span id="hlstatus"></span> </div>
</div>
</a>
</div>
</div>
`;
// Append newyly created card element to the container
container.innerHTML += content;
}
const channelList = [
{
name: "La 1",
title: "RTVE La 1",
link: "go:la1",
imgClass: "la1",
flag: "es",
url: "https://avax.dev/data/validators.json",
},
{
name: "La 2",
title: "RTVE La 2",
link: "go:la1",
imgClass: "la1",
flag: "es",
url: "https://avax.dev/data/validators.json",
},
];
// HTTP STATUS
for (let channel of channelList) {
fetch(channel.url).then(function(response) {
channel.status = response.status === 200 ? 'Online' : 'Offline';
makeStatusCard(channel);
});
}
<div id="locales"></div>

Automated id increment for bootstrap collapse component

Bootstrap's Collapse components require sections (or cards) with unique id to enable collapsing / decollapsing each section independently. I am trying to create multiple sections equal to the amount of data points using "v-for" from vue.js. However, I don't know how to automatically generate unique ids for the cards. this is what I tried:
<div id = "story-content" class="content">
<div v-for="(subchapter, chapter) in story" class="card">
<div class="card-header">
<a href = "'collapse' + generateNewId" class="card-link" data-toggle="collapse" >
[[chapter]]
</a>
</div>
<div id = "'collapse' + getCurrentId" class="collapse show" data-parent="#story-content" >
<div class="card-body">
[[subchapter]]
</div>
</div>
</div>
</div>
<script>
var story = {{story | safe}};
var app = new Vue({
delimiters: [ '[[', ']]'],
el: '#portofolio',
data: {
story: story,
uniqueId: 0,
},
methods: {
generateNewId: function() {
return uniqueId + 1;
},
getCurrentId: function() {
return uniqueId;
}
}
})
</script>
Example of the story data structure:
{
"Chapter1": {
"Subchapter1": {
"side_note": "January - June 2019",
"desc": "description here"
},
"Subchapter2": {
"side_note": "January - June 2019",
"desc": "description here"
}
},
"Chapter2": {
"Subchapter1": {
"side_note": "",
"desc": ""
}
}
}
P.S I am not using bootstrap-vue since I did not know its existence until in the middle of my learning. I'm a beginner in web development. Hopefully there is a way to solve this issue without the need of bootstrap-vue as I will need to modify other components as well.
Bootstrap 4 uses jQuery for the Collapse component. So, one way to solve it is to simply use the Chapter keys as the unique id's...
<div id="story-content" class="content">
<div v-for="(subchapter, chapter) in story" class="card">
<div class="card-header">
<a :href="'#collapse' + chapter" :data-target="'#collapse' + chapter" class="card-link"
data-toggle="collapse"> [[chapter]] </a>
</div>
<div :id="'collapse' + chapter"
class="collapse show" data-parent="#story-content">
<div class="card-body"> [[subchapter]] </div>
</div>
</div>
</div>
Demo: https://codeply.com/p/0DEYVY4HUA
However, using jQuery with Vue isn't desirable, so a better way would be to recreate the collapse behavior in Vue as explained here

Why is this template literal returning all columns in separate rows?

I'm using Bootstrap 4 on the front end, and a simple template literal to pass my strings. It's outputting the columns into their own individual rows, and I don't understand why.
const bodList = [
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
},
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
},
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
}
];
function bodTemplate(bod) {
return `
<div class="col-md-4 col-lg-3">
<div class="card border-0">
<img src="${bod.image}" class="card-img-top" alt="${bod.name}">
<div class="card-body pl-0">
<h5 class="card-title">${bod.name} <span class="text-right">${bod.termExp}</span></h5>
<h6 class="card-title">${bod.title}</h6>
<h6 class="card-title"><span class="text-muted font-weight-bold">${bod.company}</span></h6>
</div>
</div>
</div>
`;
}
document.getElementById("boardDirectors").innerHTML = `
${bodList.map(bodTemplate).join(" ")}
`;
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<div class="container-fluid">
<div class="row no-gutters">
<div id="boardDirectors"></div>
</div>
</div>
It's a bootstrap / CSS issue, rather anything related to the fact you've used template literals.
It appears that by having an extra <div> in between the row div and the col divs, you've broken the link between those two (in bootstrap's mind at least), so it doesn't treat those columns as columns. I haven't checked the source but I'd guess it's related to how the CSS rules are defined, perhaps a strict hierarchy is required.
Anyway the simple solution is to remove that div and shift the id="boardDirectors attribute onto the row div.
I also removed the no-gutters class to stop the images bunching up next to each other - now it allows some space in between them.
const bodList = [
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
},
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
},
{
image: "https://placekitten.com/450/600",
name: "First Last",
profile: "https://www.google.com",
termExp: "2023",
title: "Chief Guy",
company: "The Company"
}
];
function bodTemplate(bod) {
return `
<div class="col-md-4 col-lg-3">
<div class="card border-0">
<img src="${bod.image}" class="card-img-top" alt="${bod.name}">
<div class="card-body pl-0">
<h5 class="card-title">${bod.name} <span class="text-right">${bod.termExp}</span></h5>
<h6 class="card-title">${bod.title}</h6>
<h6 class="card-title"><span class="text-muted font-weight-bold">${bod.company}</span></h6>
</div>
</div>
</div>
`;
}
document.getElementById("boardDirectors").innerHTML = `
${bodList.map(bodTemplate).join(" ")}
`;
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<div class="container-fluid">
<div class="row" id="boardDirectors">
</div>
</div>
This is not relevant to template literals. It's CSS related.
Try adding your id on the div above:
<div id="boardDirectors" class="row no-gutters">
and remove the old one. This should solve your issue.
<div class="container-fluid">
<div id="boardDirectors" class="row no-gutters"></div>
</div>

Filter array of objects based on the objects attributes

I would like to filter an array of objects based on the objects attributes. Let me show you what I mean with the code. First of all I have an array where I store the information of the objects:
var data = [
{
product: "Haori Jacket",
url: "haorijacket.html",
image: "img/haori-jacket.jpg",
altDesc: "Jacket",
price: "$210.00",
outwear: ""
},
{
product: "Swing Dress",
url: "swingdress.html",
image: "img/swing-dress.jpg",
altDesc: "Dress",
price: "$218.00",
dress: ""
},
{
product: "Tan Tote",
url: "",
image: "img/tan-tote.jpeg",
altDesc: "Backpack",
price: "$350.00",
sale: "$475.00",
accessory: ""
},
{
product: "Sunglasses Nº 1",
url: "",
image: "img/sunglasses-n1.jpeg",
altDesc: "Sunglasses",
price: "$125.00",
accessory: ""
},
{
product: "Sunglasses Nº 2",
url: "",
image: "img/sunglasses-n2.jpeg",
altDesc: "Sunglasses",
price: "$125.00",
accessory: ""
}
];
Then dynamically generate a string using a Template Literal with a function:
// Template literal
function clothingView(item, index) {
return (`
<a href="${item.url}" class="shop-item">
${item.sale ? `<span class="shop-item__sale">Sale</span>`: ''}
<img data-src=${item.image} alt="${item.altDesc}" class="shop-item__img">
<div class="quickview">
<span class="quickview__icon">Quick View</span>
<span class="quickview__info">${item.product}
<br>
<span class="quickview__price">${item.price}
${item.sale ? `<span class="quickview__price--sale">${item.sale}</span>`: ''}
</span>
</span>
<span class="shop-item__index">${index}</span>
</div>
</a>
`);
};
// Append template literal to html structure
for (var i = 0; i < data.length; ++i) {
$('.all-items').append(clothingView(data[i], i))
}
I have a div with the class "all-items" which contain all my objects (38 to be exact) but I also want to divide these objects in categories (accesories, dresses, outwear, etc..). I am trying to do this using the filter method. Here's some images to help clarify the situation:
Basically I'd like to append to my div with the class "accesories" only the objects with the attribute "accesory". How can I do this? Any help is much appreciated!
edit: let me also include the html structure just in case:
<section class="products-container container">
<nav class="categories">
<span class="categories__link" id="accesories">Accesories</span>
<span class="categories__link" id="bottoms">Bottoms</span>
<span class="categories__link" id="dresses">Dresses + Jumpsuits</span>
<span class="categories__link" id="outwear">Outerwear</span>
<span class="categories__link" id="tops">Tops</span>
<span class="categories__link" id="sale">— Sale</span>
</nav>
<div class="products all-items">
<!-- <a href="haorijacket.html" class="shop-item">
<span class="shop-item__sale">Sale</span>
<img src=img/haori-jacket.jpg alt="Jacket" class="shop-item__img">
<div class="quickview">
<span class="quickview__icon">Quick View</span>
<span class="quickview__info">$Haori Jacket
<br>
<span class="quickview__price">$210.00<span class="quickview__price--sale">$150.00<span></span>
</span>
<span class="clothing-index">${index}</span>
</div>
</a> -->
</div>
<div class="products accesories"></div>
<div class="products bottoms"></div>
<div class="products dresses"></div>
<div class="products outwear"></div>
<div class="products tops"></div>
<div class="products sale"></div>
</section>
You can use the in operator to check if a specific property exists within an object.
The in operator returns true if the specified property is in the specified object or its prototype chain.
var allItems = $('div.all-items');
var accesoryItems = $('div.accesories');
for (var i = 0; i < data.length; ++i) {
var clothingView = clothingView(data[i], i);
if ('accessory' in data[i]) accesoryItems.append(clothingView);
else allItems.append(clothingView);
}
Of course, you need to add the necessary if-else-if to add the views to specific divs.
You can try this:
function filterItems(itemType) {
return data.filter(function(i) {return i[itemType] !== undefined});
}
This should be okay for IE9+ and modern browsers.

ng-repeat on bootstrap tab-content/tab-pane

I am having trouble getting my tab content to appear properly on page load. What I have is a factory of Objects called apiList, I then use two ng-repeats, one which hits each object in the apiList, then the next one which iterates through that object and puts all of its data on the page. I use #tab{{$index}} to keep my data-toggles aligned between the buttons and tab-panes.
The problem seems to be with how I use the active attribute on my tab-pane.
I have three known test cases so far.
I can only get information from the first Object by using the condition ng-class="{ 'active': $index == 0}" as in..
<div ng-repeat="(key, data) in apiList[0]" class="tab-pane active" id="tab{{$index}}" ng-class="{ 'active': $index == 0}">
If I remove the conditional from the line then nothing appears
And if I just add active to the pane value (with no condition)
(i.e. <div ng-repeat="(key, data) in apiList[0]" class="tab-pane active" id="tab{{$index}}"> They all appear.
So my problem seems to be with how I need to turn on/off my active for the ng-repeat and I am just getting lost.
Also, clicking on accounts/customers does not update the tabs. They both have the right data-toggle ID's (0 and 1) in respect to the tab-panes so I assume it is part of the active issue. And whenever I click on my tab panes, they do expand just fine.
Here is my Factory, ng-repeat(s), and the code that was my original setup (functional).
Factory
.factory('APIMethodService', [function() {
var Head = "api.verifyvalid";
return {
apis: [
{
accounts: [
{
parameters : [
{
name : "Accounts",
version : "1.0"
}
],
uri: Head + "/v1/accounts/account_number",
methods : [
{
name: "Account Number",
desc: "Returns the account number."
}, {
name: "Account Money",
desc: "Returns the monetary amount within the account."
}
]
},
{
parameters : [
{
name : "Accounts",
version : "2.0"
}
],
uri: Head + "/v2/accounts/account_number",
methods: [
{
name: "Account Number",
desc: "Returns the account number."
}, {
name: "Account Money",
desc: "Returns the monetary amount within the account."
}, {
name: "Account Token",
desc: "Returns the account's token."
}
]
}
],
customers:[
{
parameters : [
{
name : "Customers",
version : "1.0"
}
],
uri: Head + "/v1/customers/customer_number",
methods : [
{
name: "Customer Name",
desc: "Returns the customer's name."
}, {
name: "Customer ID",
desc: "Returns the customer's ID."
}
]
},
{
parameters : [
{
name : "Customers",
version : "2.0"
}
],
uri : Head + "/v2/customers/customer_number",
methods: [
{
name: "Customer Name",
desc: "Returns the customer's name."
}, {
name: "Customer ID",
desc: "Returns the customer's ID."
}, {
name: "Customer Email",
desc: "Returns the customer's email."
}
]
}
]
}
]
};
ng-repeat (just the right-hand tabs)
<div class="col-md-9">
<div class="tab-content">
<div ng-repeat="(key, data) in apiList[0]" class="tab-pane active" id="tab{{$index}}">
<div ng-repeat="api in apiList[0][key]">
<div class="panel panel-info" id="panel{{$index}}">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-target="#collapse{{key}}{{$index}}" class="collapsed">
{{api.uri}}<i class="newTab" ng-click="apiTab(api)">(Open in new tab)</i>
</a>
</h4>
</div>
<div id="collapse{{key}}{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table">
<tr ng-repeat="method in api.methods">
<td>{{method.name}}</td>
<td>{{method.desc}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The following code is what I originally had, before trying to crunch it down more
<div class="col-md-9" style="display:none">
<div class="tab-content">
<!-- Accounts -->
<div class="tab-pane active" id="tab0">
<div ng-repeat="api in apiList[0].accounts">
<div class="panel panel-info" id="panel0">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-target="#collapseAccountsV{{$index}}" class="collapsed">
{{api.uri}}
</a>
<i class="newTab" ng-click="apiTab(api)">(Open in new tab)</i>
</h4>
</div>
<div id="collapseAccountsV{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table">
<tr ng-repeat="method in api.methods">
<td>{{method.name}}</td>
<td>{{method.desc}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Customers -->
<div class="tab-pane" id="tab1">
<div ng-repeat="api in apiList[0].customers">
<div class="panel panel-info" id="panel1">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-target="#collapseCustomersV{{$index}}" class="collapsed">
{{api.uri}}<i class="newTab" ng-click="apiTab(api)">(Open in new tab)</i>
</a>
</h4>
</div>
<div id="collapseCustomersV{{$index}}" class="panel-collapse collapse">
<div class="panel-body">
<table class="table">
<tr ng-repeat="method in api.methods">
<td>{{method.name}}</td>
<td>{{method.desc}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Other -->
<div class="tab-pane fade" id="tab3">
<!-- TBA -->
</div>
</div>
</div>
Noob mistake, everything works fine! I was using my old code as the base outline on the same page and had set that old code to style="display:hidden" but this still meant that the ID's were apart of the DOM, hence why I couldn't change my tab's properly (duplicate/conflicting ID's).

Categories