In a javascript file I currently have some HTML saved into a variable.
However I only want to display the middle section of the HTML on a condition. See the if code.length == 1.
var html = `<div class="flex justify-between p-3 border-b border-blue-200" id=${this.id}><div> <h5 class="font-bold text-blue-700 text-sm mb-1 pr-2"> ${Name}</h5> <p class="text-sm text-blue-500"> if (Code.length == 1) { <span class="font-semibold mr-1"><%= t("common.code") %></span> <span> </span> } </p></div></div>`
However I can't seem to get this working. Is this possible?
That line is too long to be maintainable. Break it up so you can see what's going on.
var html = `<div class="flex justify-between p-3 border-b border-blue-200" id=${this.id}><div> <h5 class="font-bold text-blue-700 text-sm mb-1 pr-2"> ${Name}</h5> <p class="text-sm text-blue-500">`;
if (Code.length == 1) {
html += `<span class="font-semibold mr-1"><%= t("common.code") %></span> <span> </span>`;
}
html += `</p></div></div>`
Use a variable
In your HTML snippet you are already using variables. Why not stick to that by making the content a variable. See snippet below with values added as an example using a variable content.
This part seems prepared server-side: <%= t("common.code") %>. You know how to do that yourself I'm assuming.
let Code = 'K';
let id = '5'; // this.id;
let Name = 'Herring';
var content = Code.length == 1 ? `<span class="font-semibold mr-1"><%= t("common.code") %></span>` : '';
var html = `<div class="flex justify-between p-3 border-b border-blue-200" id="${id}"><div>
<h5 class="font-bold text-blue-700 text-sm mb-1 pr-2">${Name}</h5>
<p class="text-sm text-blue-500">${content}</p>
</div></div>`;
console.log(html);
Related
As you can this is a string js and I want to use onClick on the input whose view is being toggled by selecting the boolean value edit. Please suggest how to use onchnage here.
Already tried normal HTML onchange (not working)
onchange="${onchnage}"
Pls, suggest if you happen to know the answer.
export const DefaultNode = (d, selectedNodeIds, edit, fomatOptions, inputOnclick) => {
const mainData = d.data.data
return `<div style='background:${selectedNodeIds.length!==0 ? (selectedNodeIds.includes(d.data.id) ? `rgba(${ fomatOptions.nodeBg.r }, ${ fomatOptions.nodeBg.g }, ${ fomatOptions.nodeBg.b }, ${ fomatOptions.nodeBg.a })`: "#fff"): `rgba(${ fomatOptions.nodeBg.r }, ${ fomatOptions.nodeBg.g }, ${ fomatOptions.nodeBg.b }, ${ fomatOptions.nodeBg.a })`};
color:${selectedNodeIds.length!==0 ?(selectedNodeIds.includes(d.data.id) ?`rgba(${ fomatOptions.textColor.r }, ${ fomatOptions.textColor.g }, ${ fomatOptions.textColor.b }, ${ fomatOptions.textColor.a })`:'#000'): `rgba(${ fomatOptions.textColor.r }, ${ fomatOptions.textColor.g }, ${ fomatOptions.textColor.b }, ${ fomatOptions.textColor.a })`}'
class=${`"w-[250px] p-3 rounded-[15px] relative border-[3px] h-[140px] ${selectedNodeIds.includes(d.data.id)? 'drop-shadow-md' :"shadow"} ${ selectedNodeIds.includes(d.data.id) && fomatOptions.fontFamily.value}"`}>
<div class='flex justify-between w-full '>
<div class="">
${edit? `<input onclick='${inputOnclick}' class="fullName text-[13px] font-semibold" value="${mainData.name}"/>` : `<div class=" text-[13px] font-semibold">${mainData.name} </div>`}
<div class=" text-[11px] opacity-70 mt-0.5 font-medium">${mainData.position } </div>
<div class='mt-2'>
<div class=" text-[11px] opacity-70 mt-0.5 font-medium">${mainData.email } </div>
<div class=" text-[11px] opacity-70 mt-0.5 font-medium">${mainData.phone } </div>
</div>
</div>
<img class='w-10 h-10 mr-2 rounded-[10px]' src=${mainData.imgUrl} />
</div>
<div class='flex pt-4 justify-between items-center'>
<p class='text-[10px] font-medium uppercase bg-theme-gray px-2 text-black rounded-full py-0.5'>${mainData.department}</p>
<p class='text-[10px] font-medium uppercase mr-2'>${mainData.location}</p>
</div>
${((selectedNodeIds.includes(d.data.id))) ? `<div class="absolute left-4 -top-5 font-semibold text-[10px] p-1 bg-gray-400 text-white rounded-t-md">
Selected
</div>`: `<p></p>`}
</div>`
}
I believe what you're missing here is the different naming conventions for default HTML event listeners in React, not all of your code is here so I'm assuming you do not have a custom function called onchange, but in React its called onChange (or onClick, etc) so you're looking something like this for your code snippet.
onChange="${onchnage}"
Also double-check to make sure you have all your syntax and spelling correct. Also for writing better JSX for returning HTML elements you can write code like the following
return (
<div>
<p>Text here</p>
</div>
);
I have a product that I want to programatically set a Checkout Session URL and then redirect a user when they click on an tag.
const PlanComponent = () => {
const [tiers, setTiers] = useState([]);
async function CheckoutSessionUrl(tierId) {
var result = null
await CreateCheckoutSession(
"PRODUCT_ID",
tierId,
"UID"
).then(function(response) {
result = response
})
return result;
};
async function LoadProducts() {
var result = []
await GetProducts("PRODUCT_ID").then(function(response) {
for (var i = 0; i < response.length; i++) {
var tier_id = response[i]["tier_id"]
CheckoutSessionUrl(tier_id).then(function(tier_response) {
response[i]["url"] = tier_response;
})
}
console.log("printing tiers");
console.log(response);
return response;
}).then(function(response){
result = response;
setTiers(result)
return result;
});
return result;
}
useEffect(() => {
// Some initialization logic here
LoadProducts().then(function(response) {
console.log("setting tiers")
console.log(response)
//setTiers(response)
})
}, []);
return (
<div className="bg-white">
<div className="max-w-7xl mx-auto py-24 px-4 sm:px-6 lg:px-8">
<div className="sm:flex sm:flex-col sm:align-center">
<h1 className="text-5xl font-extrabold text-gray-900 sm:text-center">Pricing Plans</h1>
<p className="mt-5 text-xl text-gray-500 sm:text-center">
Start building for free, then add a site plan to go live. Account plans unlock additional features.
</p>
</div>
<div className="mt-12 space-y-4 sm:mt-16 sm:space-y-0 sm:grid sm:grid-cols-2 sm:gap-6 lg:max-w-4xl lg:mx-auto xl:max-w-none xl:mx-0 xl:grid-cols-4">
{tiers.map((tier) => (
<div key={tier.name} className="border border-gray-200 rounded-lg shadow-sm divide-y divide-gray-200">
<div className="p-6">
<h2 className="text-lg leading-6 font-medium text-gray-900">{tier.name}</h2>
<p className="mt-4 text-sm text-gray-500">{tier.description}</p>
<p className="mt-8">
<span className="text-4xl font-extrabold text-gray-900">${tier.price}</span>{' '}
<span className="text-base font-medium text-gray-500">/mo</span>
</p>
<a
href={tier.url}
className="mt-8 block w-full bg-gray-800 border border-gray-800 rounded-md py-2 text-sm font-semibold text-white text-center hover:bg-gray-900"
>
Buy {tier.name}
</a>
</div>
<div className="pt-6 pb-8 px-6">
<h3 className="text-xs font-medium text-gray-900 tracking-wide uppercase">What's included</h3>
<ul role="list" className="mt-6 space-y-4">
{tier.users.map((feature) => (
<li key={feature} className="flex space-x-3">
{/*<CheckIcon className="flex-shrink-0 h-5 w-5 text-green-500" aria-hidden="true" />*/}
<span className="text-sm text-gray-500">{feature}</span>
</li>
))}
</ul>
</div>
</div>
))}
</div>
</div>
</div>
)
}
so if you look at the href={tier.url} it's not being set correctly. I feel like I'm not doing this correctly. Would love some feedback on how to actually get this working properly. IT looks like the tier.url new field isn't being set correctly (doesn't exist in the initial request but all the other attributes work).
The other option I wanted to do was when a user clicked a Button, it would generate a URL and redirect a user to that new external url but the navigation kept breaking.
Oh I found out what was happening. I needed to replace
await GetProducts("PRODUCT_ID").then(function(response) {
with
await GetProducts("PRODUCT_ID").then(async function(response) {
This question already has answers here:
Unexpected comma using map()
(4 answers)
Closed last year.
Ok so i have hacked something together it works as intended but I get a comma between entries more than one.
I have this
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
let markup = '';
markup = `
<section>
<div class="inner-element">
<div class="question flex justify-between px-6 py-4 bg-purple-800">
<span class="text-base text-white font-bold">HCP365 Pixels</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
${HCP365Object.sitePixels.map((x) => x)}
${HCP365Object.searchPixels.map((x) => x)}
${HCP365Object.emailPixels.map((x) => x)}
${HCP365Object.programmaticPixels.map((x) => x)}
</div>
</div>
<div class="inner-element">
<div class="question flex justify-between px-6 py-4 bg-gray-500">
<span class="text-base text-white font-bold">NON HCP365 Pixels</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
${HCP365Object.nonHCP365Pixels.map((x) => x)}
</div>
</div>
`;
markup += '</section>';
sendResponse(markup);
});
Which in turn gives me this:
Where the little bugger is here:
Between the element which is :
const pixelInfo = `
<div class="element">
<div class="question flex justify-between px-6 py-4 ${colorGrade}">
<span class="text-base text-white font-bold">${pixelType}</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
<span id="pixel-url" class="c-word-wrap text-sm font-mono">${pixelUrl}</span>
<span id="query-params">${queryParams}</span>
</div>
</div>
`;
Each pixelInfo is pushed into it's own array which is within an object. Is this comma here because I am mapping through an array and it's chucking out the , ? Is there a way to get rid of it?
This is my whole code
const HCP365Object = {
sitePixels: [],
searchPixels: [],
emailPixels: [],
programmaticPixels: [],
nonHCP365Pixels: [],
};
// Function to break down the http request into our pixel url with a subset of associating query params.
const onBeforeSendHeadersListener = function (details) {
let regex = /[?&]([^=#]+)=([^&#]*)/g,
pixelType,
pixelUrl = `${details.url}`,
queryParams,
params = {},
match,
colorGrade;
if (details.url.includes('&ch=1&')) {
pixelType = 'HCP365 Site Pixel';
colorGrade = 'bg-purple-600';
} else if (details.url.includes('&ch=2&')) {
pixelType = 'HCP365 Search Pixel';
colorGrade = 'bg-purple-500';
} else if (details.url.includes('&ch=3&')) {
pixelType = 'HCP365 Email Pixel';
colorGrade = 'bg-purple-400';
} else if (details.url.includes('&ch=4&')) {
pixelType = 'HCP365 Programmatic Pixel';
colorGrade = 'bg-purple-300';
} else {
pixelType = 'Non HCP365 PP Pixel';
colorGrade = 'bg-gray-400';
}
// Splitting url's query params out to key value pairs
while ((match = regex.exec(details.url))) {
params[match[1]] = match[2];
}
// Looping through object's key value pair to place into divs
for (const [key, value] of Object.entries(params)) {
queryParams += `
<div class="text-sm my-1">
<span class="font-bold uppercase mr-1">${key}: </span>
<span class="font-normal font-mono capitalize c-word-wrap">${value}</span>
</div>
`;
}
const pixelInfo = `
<div class="element">
<div class="question flex justify-between px-6 py-4 ${colorGrade}">
<span class="text-base text-white font-bold">${pixelType}</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
<span id="pixel-url" class="c-word-wrap text-sm font-mono">${pixelUrl}</span>
<span id="query-params">${queryParams}</span>
</div>
</div>
`;
// push the relevant pixel into the correct array
if (details.url.includes('&ch=1&')) {
HCP365Object.sitePixels.push(pixelInfo);
} else if (details.url.includes('&ch=2&')) {
HCP365Object.searchPixels.push(pixelInfo);
} else if (details.url.includes('&ch=3&')) {
HCP365Object.emailPixels.push(pixelInfo);
} else if (details.url.includes('&ch=4&')) {
HCP365Object.programmaticPixels.push(pixelInfo);
} else {
HCP365Object.nonHCP365Pixels.push(pixelInfo);
}
return HCP365Object;
};
// Apply the function entered to each header coming from contextweb domain
chrome.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeadersListener,
{
urls: ['https://*.contextweb.com/bh/*'],
},
['requestHeaders']
);
// Initiate connection to send Message over to popup.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
let markup = '';
markup = `
<section>
<div class="inner-element">
<div class="question flex justify-between px-6 py-4 bg-purple-800">
<span class="text-base text-white font-bold">HCP365 Pixels</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
${HCP365Object.sitePixels.map((x) => x)}
${HCP365Object.searchPixels.map((x) => x)}
${HCP365Object.emailPixels.map((x) => x)}
${HCP365Object.programmaticPixels.map((x) => x)}
</div>
</div>
<div class="inner-element">
<div class="question flex justify-between px-6 py-4 bg-gray-500">
<span class="text-base text-white font-bold">NON HCP365 Pixels</span>
<button><i class="fas fa-plus-circle"></i></button>
</div>
<div class="answer hideText">
${HCP365Object.nonHCP365Pixels.map((x) => x)}
</div>
</div>
`;
markup += '</section>';
sendResponse(markup);
});
I know it's very hacky! But it works
Taking another look at
markup = `
...
<div class="answer hideText">
${HCP365Object.nonHCP365Pixels.map((x) => x)}
</div>
...
`;
The problem is HCP365Object.nonHCP365Pixels.map((x) => x). map() returns an array, and calling toString() will list all items separated by commas.
You will need to join() these to build the content without the commas.
Also, since .map((x) => x) just returns a copy of the array you can get rid of that too.
markup = `
...
<div class="answer hideText">
${HCP365Object.nonHCP365Pixels.join('')}
</div>
...
`;
You should use .join('') everywhere you use .map((x) => x)
I have been working on a sorting system lately with VueJs and Laravel but sort of got stuck on a piece of code that actually works, tho I don't think it's efficient because I'm using a v-if and a v-for in the same element. It is as following:
<!-- Activity table (small breakpoint and up) -->
<div class="hidden sm:block">
<div class="max-w-6xl px-4 mx-auto sm:px-6 lg:px-8">
<div class="flex flex-col mt-2">
<div class="min-w-full overflow-hidden overflow-x-auto align-middle shadow sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-500 uppercase bg-gray-50">
Medewerker
</th>
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-500 uppercase bg-gray-50">
Laatst goedgekeurde datum
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200" >
<tr v-for="data in Medewerkers" :key="data.medewerkers" class="bg-white" v-if="data.timesheets.length !== 0"> <!-- This is the timesheet check function v-if="data.timesheets.length !== 0" -->
<td class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-500 uppercase bg-gray-50">
{{ data.mw_naam }}
</td>
<td class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-500 uppercase bg-gray-50">
{{ data.timesheets[0].datum }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
My data object:
data() {
return {
Medewerkers: null,
aantalOpenstaande: null,
laatstBijgewerkt: null,
}
},
My methods:
// Event fire die opgevangen wordt in Admin.vue om de tab te veranderen
changetab(data) {
this.$emit('update-admin-sidenav-tab', data);
},
updateOpenTimesheets() {
axios.post('admin/fetch', {}).then(response => {
this.aantalOpenstaande = response.data.count;
this.laatstBijgewerkt = response.data.timestamp;
// Fire an event to have the "Openstaand" refresh it's data aswel.
EventBus.fire('refreshAdminOpenTimesheets', response.data.timesheets);
});
}
},
created() {
axios.get(`admin/fetchemployeewithlastsubmitteddate`).then(response => {
this.Medewerkers = response.data;
});
this.updateOpenTimesheets();
setInterval(() => {
this.updateOpenTimesheets();
}, 60000);
},
}
Yes, I'm using Tailwind with it if you ever wondered.
So the code is self-explanatory I think. I'm requesting data from the database and inserting it into a table (Not the whole code is shown, only the part where I get data from the timesheet table). The thing is, I wanna know how do I use the computed properly to be getting the same data and then referencing it so the (datum) property can read it as well. I did try it but no luck so far and this is what I came up with:
computed: {
timeMedewerkers: function () {
this.data.timesheets.filter(Medewerkers => Medewerkers.timesheets.length !== 0);
}}
I am still a junior dev so I might be missing something, I would appreciate it if you don't criticize me for whatever reason. I'm open to tips and suggestions tho. Thanks in advance!
This is what it looks like when fully compiled: This is the compiled version, it returns the names requested from the timesheet table
I have expanded this code for my own learning abilities. I understand I can definitely shorten this down a LOT but I am trying to learn and expand my frontend experience.
So I have the code below. When localstorage it set to true/false it picks up the right v-if/else section. Now, what I need to do is set the local storage based on button click.
What is the best way to accomplish this?
<div v-if="privateChat == 'false'">
<button type="button">
<a key="privateChat" href="#" class="bg-red-900 text-gray-100 hover:bg-gray-800 hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium">
<ChatIcon class="h-6 w-6 text-white"/>
<span class="pt-2">Private Chat OFF</span>
</a>
</button>
</div>
<div v-else>
<button type="button">
<a key="privateChat" href="#" class="bg-green-900 text-gray-100 hover:bg-gray-800 hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium">
<ChatIcon class="h-6 w-6 text-white"/>
<span class="pt-2">Private Chat ON</span>
</a>
</button>
</div>
<script>
export default {
data() {
return {
privateChat: (localStorage.getItem("privateChat") === 'true') ? 'true' : 'false',
}
},
methods: {
clickPrivateChat (value) {
this.privateChat = value === true ? "true" : "false";
localStorage.setItem("privateChat", value);
},
setup() {
const enabled = ref(privateChat)
let value = localStorage.getItem("privateChat");
let privateChat = (value === 'true');
}
</script>
There are several improvements you can make...
use actual true/false values instead of "true", "false" strings
DRY: you just need one button; use a Vue computed value to show "ON" or "OFF"
use conditional :class logic to apply bg-green-900 class
script:
data() {
return {
privateChat: (localStorage.getItem("privateChat") === true) ? true : false,
}
},
computed: {
onOrOff() {
return this.privateChat ? 'ON' : 'OFF'
}
},
methods: {
clickPrivateChat (value) {
this.privateChat = !this.privateChat
localStorage.setItem("privateChat", value)
},
setup() {
const enabled = ref(privateChat)
let value = localStorage.getItem("privateChat")
let privateChat = (value === true)
}
},
markup:
<div>
<button type="button" #click="clickPrivateChat">
<a key="privateChat" href="#" :class="privateChat?'bg-green-900':''" class="bg-red-900 text-gray-100 hover:bg-gray-800 hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium">
<span class="pt-2">Private Chat {{ onOrOff }}</span>
</a>
</button>
</div>
improved Vue approach