I am writing a webpage about games. In this there is a page in which categories of games should be diplayed, when one is clicked, the games within this category should then appear underneath it.
This is an extract from the html file, I believe the issue is arising when i use the and tag. As they stay constant through each iteration, when i click one category, all categories display their repsective games, rather than just the one selected.
{% if games %}
<h1> Games</h1>
{% for catergory in games %}
<highlight><strong><toggleButton>{{ catergory.0.get_catergory_display }} </toggleButton></strong><highlight>
<ul>
{% for game in catergory %}
<catGames><li><highlight> {{game.name}} : <i>
{% if game.rating != -1 %}
{{game.rating}}
{% else %}
unrated
{% endif %}
</i></highlight></li></catGames>
{% endfor %}
</ul>
<br/>
{% endfor %}
{% else %}
<strong> There are no games present.</strong>
{% endif %}
here is the jquery file
$(document).ready( function() {
$('toggleButton').click(function() {
if ($('catGames').is(':hidden')) {
$('catGames').show();
} else {
$('catGames').hide();
}
});
});
I was wondering if there was an easier solution than having to manually type out each category, and getting rid of the for-loop. It is also causing problems with the jquery which highlights the text being hovered over, lighting all of the categorys and games, rather than just the one being hovered.
You have to specific what is the right <catGames>
Try this different way :
First one :
$('toggleButton').click(function(e) {
const cat = $(e.currentTarget).closest('h1').next('ul').find('catGames');
cat.is(':hidden') ? cat.show() : cat.hide();
});
Second one (best way for me) :
Wrap each catergory with a <div class='catergory'> for example and try this :
$('div.catergory').on('click', 'toggleButton', function(e){
const cat = $(e.delegateTarget).find('catGames');
cat.is(':hidden') ? cat.show() : cat.hide();
});
$(e.delegateTarget) focus the main container whose contain the <catGames>
No the problem is not about loop. Its about how you create elements inside loop and its about how you reference them with onlick even.
so this is one way to fix is:
$(document).ready( function() {
$('toggleButton').click(function() {
if ($(this).parent('highlight').next('ul').find('catGames').is(':hidden')) {
// this way you try to point to the corresponding ul tag next
// to the toggle botton and try to hide and show the whole ul
$(this).parent('highlight').next('ul').find('catGames').show();
} else {
$(this).parent('highlight').next('ul').find('catGames').hide();
}
});
});
So About section you said is there a better solution for the category and opening and closing categories yes there is. Have you checked https://v4-alpha.getbootstrap.com/components/collapse/. I believe you can use the functionality and customized it based on your needs. If you had problem using it let me know.
Related
The below code is slightly different than what is rendered, I haven't pushed my changes yet. So keep that in mind.
It is supposed to
iterate through the YAML data file.
place a link everywhere that is required of it.
However, currently, it is only placing the last element seen by the for loop everywhere I want a link.
I have a YAML file with two links, and instead of placing the link in the block associated with its PID, it is placing the second link in all link locations.
I am using REGEX to parse, so anywhere in the YAML file that is aaaa a link gets replaced at that location. That works, it just doesn't place the right link.
Now the even more confusing part is that the first console.log console.log(faqLink{{ faq_link_pid }}); prints all of the links, correctly and in the order, they are in the file.
<h1 class="fs-6 fw-500" align="center">Frequently Asked Questions <br> Welcome to our FAQ!</h1>
<div class="accordiobody">
{% for faq in site.data.faq_yaml.frequently_asked_questions %}
<div class="accordion">
<hr>
<div class="container">
<div class="question fw-400">
<h1 class="fs-5 fw-500">
{{ faq.question }}
</h1>
</div>
<div class="answer">
<blockquote>
<span class="answerspan">
{{ faq.answer }}
</span>
</blockquote>
</div>
</div>
</div>
{% endfor %}
</div>
<script type="text/javascript">
{% assign faq_link = "" %}
{% assign faq_link_description = "" %}
{% assign faq_link_pid = 0 %}
{% for faq in site.data.faq_yaml.frequently_asked_questions %}
{% if faq.hyper_link != null and faq.hyper_link != "" %}
{% assign faq_link = faq.hyper_link %}
{% assign faq_link_pid = faq.faq_link_pid %}
const faqLink{{ faq_link_pid }} = "{{ faq_link }}";
{% if faq.link_description != null and faq.link_description != "" %}
{% assign faq_link_description = faq.link_description %}
const faqLinkDescription{{ faq_link_pid }} = "{{ faq_link_description }}";
console.log(faqLink{{ faq_link_pid }});
function createElement() {
for (let x in accordion) {
const link{{ faq_link_pid }} = `${faqLinkDescription{{ faq_link_pid }}}`;
console.log(link{{ faq_link_pid }});
replaceLink(link{{ faq_link_pid }});
}
}
{% endif %}
window.addEventListener('load', function () {
createElement();
});
{% endif %}
{% endfor %}
const accordion = document.getElementsByClassName('container');
for (i = 0; i < accordion.length; i++) {
accordion[i].addEventListener('click', function () {
this.classList.toggle('active');
})
}
function replaceLink(str) {
const link = document.querySelectorAll('.answerspan');
const all_link = link.forEach(function (link) {
const hyper_link = link.innerHTML;
link.innerHTML = hyper_link.replace(/aaaa./g, str);
});
}
</script>
The YAML file:
---
# Use this YAML file to create a list of FAQ questions and answers.
- question: "How will this work?"
answer: "Currently, a camera is mounted inside the headset for each eye. The camera streams through wifi to a PC client which processes and sends eye-tracking data to VR Chat."
hyper_link: ""
link_description: ""
faq_link_pid: 3
- question: "What features will be supported?"
answer: "The goal is eye tracking with eye openness and some form of pupil dilation. A far away aspiration of this project is some form of weak foveated rendering because it's cool and any small performance increase in VR is welcome."
hyper_link: ""
link_description: ""
faq_link_pid: 4
- question: "When will this be completed?"
answer: "When it's done 😉 I have a semi-busy life so development may slow and speed up inconsistently. I have a goal to be done with all base features in June."
hyper_link: ""
link_description: ""
faq_link_pid: 5
- question: "Will IR damage my eyes?"
answer: "This project has safety in mind. If you do all of the safety measures we put in place and visually test the amount of IR light you will be fine. Please note we have not finished development of all safety stuff so be careful aaaaa ."
hyper_link: "https://dammedia.osram.info/media/bin/osram-dam-2496608/AN002_Details%20on%20photobiological%20safety%20of%20LED%20light%20sources.pdf"
link_description: "here is a pdf with safety information"
faq_link_pid: 6
- question: "How expensive will this be?"
answer: "My goal is to keep it as cheap as possible with around $75 as the absolute max, with current projections being around $25-40"
hyper_link: ""
link_description: ""
faq_link_pid: 7
- question: "How do I set up my avatar?"
answer: "Check out the VR Chat face tracking wiki on our GitHub. Keep in mind that we currently only support float parameters. aaaa "
hyper_link: "https://google.com"
link_description: "Google"
faq_link_pid: 8
---
Why would you use regex + javascript to place the link? It's best to just put everything you want hidden in the HTML inside a <DIV class=hidden"> and then toggle a CSS property display:none for the DIV using javascript.
This would also work better with browsers with js turned off. More specifically: write everything in the HTML and leave the display on the DIVs you want hidden (i.e. do not set any display on the CSS file). Then use js to place upon the page loading a display:none in all these DIV elements; then use js to toggle the display for a single element.
E.g. using jquery, you would do something like
jQuery(document).ready(function($) {
//Set default open/close settings
var divs = $('.hidden').hide(); //Hide/close all containers
and then on the clickable element use slideToggle() to toggle the display of the next element (you will have to look at your DOM tree to get exactly which element)
I solved my issue by delting all of the javascript and REGEx and simply using the Liquid replace function. No JS needed. I was just over-complicating it because i hadn't read the liquid documetnation well enough :)
<span class="answerspan{{ faq.faq_link_pid }}">
{%- capture editable_part -%}
{{ faq.link_description }}
{%- endcapture -%}
{% if faq.answer contains 'aaaa ' %}
{{ faq.answer | replace: 'aaaa ', editable_part }}
{% else %}
{{ faq.answer }}
{% endif %}
</span>
Here in my Django code, I have a list of prices. Now I gave them unique IDs which works well, but when I try to add a click event, the click event only works for only one list item continuously.
{% for price in logistic_branch_pricing %}
<h1 id="select-delivery-location-{{price.id}}"
onclick="calculateDeliveryPrice()">{{ price.id }}-{{price.small_kg_price}}
</h1>
{% endfor %}
{% for price in logistic_branch_pricing %}
<script>
function calculateDeliveryPrice() {
var omo = document.getElementById("select-delivery-location-{{ price.id }}")
omo.classList.add('d-none')
console.log(omo)
}
</script>
{% endfor %}
You don't have to add loop over your <script> tag just pass event keyword inside your javascript onclick function like this
{% for price in logistic_branch_pricing %}
<h1 id="select-delivery-location-{{price.id}}" onclick="calculateDeliveryPrice(event)">{{ price.id }}-{{price.small_kg_price}}
</h1>
{% endfor %}
and inside your javascript do like this
<script>
function calculateDeliveryPrice(e) {
var omo = e.target
omo.classList.add('d-none')
var small_kg_price = omo.textContent.split('-')[1] // return small_kg_price
console.log(omo) // returns element
console.log(omo.id) // returns id of element
}
</script>
I worked all day on it and impossible to figure it out so I need some help :)
I try to add some text on each variant line of my "Size" dropdown on my product page :
if the product quantity > 0 : Size + Quick Delivery
else : Size + 2-3 weeks delivery
Just want to display it to the customer before the click, so I don't want it just on the selectedVariant.
I tried to change it by my script.js, I was thinking to :
copy each variant quantity (I didn't find the way to do it)
copy my Dropdown in a list value/key + add text (Quick/2-3 weeks) depending of the variant quantity
var optionsSizes = {};
var optionsSizes = {};
$('#mySizes option').each(function(){
optionsSizes[$(this).val()] = $(this).text() + variant.inventory_quantity;
});
//console.log(optionsSizes);
var $el = $("#mySizes");
$el.empty(); // remove old options
$.each(optionsSizes, function(value,key) {
$el.append($("<option></option>")
.attr("value", value).text(key));
});
The copy/paste of the dropdown work but that's all.
It was easy to do it on variantSelected but that's not what I want.
Please feel free to ask if you have any question.
Cheers,
bkseen
('#product-select-5916642311-option-0') and $('#mySizes') this select elements are not in your theme by default. A Shopify or theme script adds these two elements based on the product's JSON information available via Shopify. Hence there is no direct way to get the desired result.
Here's the trick that can achieve what you desire.
Load all the variants and their required properties into a JSON object. To do this add <script>variantsJSON = {}</script> at the top of the liquid file.
Now load the variants in the following structure:
variantsJSON = {
"variant_option1" : {
"variant_option2_1_title" : "variant_option2_1_quantity",
"variant_option2_2_title" : "variant_option2_2_quantity",
} ....
}
To get the above structure, you need to add the following script inside {% for variant in product.variants %} or a similar loop in your liquid file.
<script>
if (!variantsJSON['{{ variant.option1 }}']){
variantsJSON['{{ variant.option1 }}'] = {}
}
{% assign availability = 'QUICK DELIVERY' %}
{% if variant.inventory_quantity == 0 %}{% assign availability = '2-3 WEEKS DELIVERY' %}{% endif %}
if (!variantsJSON['{{ variant.option1 }}']['{{ variant.option2 }}']){
variantsJSON['{{ variant.option1 }}']['{{ variant.option2 }}'] = '{{ availability }}'
}
</script>
The above snippet (possible refinement required) will load all the variants and their availability into the JSON object
Now all you need to do is trigger a function on change of $('#product-select-{{ product.id }}-option-0') which will clear all <li>s in $('#mySizes'), then populates them using the values stored in variantsJSON's variant_option2 & variant_availability of the selected variant_option1
P.S. Feel free to format my answer. I'm somehow unable to get the right formatting.
To answer Hymnz on
That's tricky but I think I can help. How are you changing the span with the classes product__inventory-count product__form-message--success ? – HymnZ 10 hours ago
Blockquote
if (variant) {
{% if settings.product_show_shipping %}
var myCount = variant['inventory_quantity'];
var myPath = this.element.find('.product__inventory-count');
if (myCount < 1){
myPath.removeClass('product__form-message--success');
myPath.addClass('product__form-message--error');
myPath.text("2-3 weeks delivery");
}else{
//myPath.toggleClass('product__form-message--success').siblings().removeClass('checked');
myPath.removeClass('product__form-message--error');
myPath.addClass('product__form-message--success');
myPath.text("Quick delivery");
}
{% endif %}
The thing is, variant is the variant selected and not going through all the product's variants.
I am new to coding, but have been reading about DRY - Don't Repeat Yourself.
I have a JavaScript if/else statement that does not fit the DRY approach, but I am unable to workout how to write the JavaScript if/else statement so that the contents are not repeated.
I am hoping some one smarter than me can show me.
Here is my code:
{% if user.get_profile.subscription_category == '00' %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
$('#id_name_details_middle_name').removeClass('kmw-disabled');
$('#id_name_details_last_name').removeClass('kmw-disabled');
$('#id_name_details_suffix_title').removeClass('kmw-disabled');
{% else %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% endif %}
{% endif %}
The contents of the 1st if are repeated in the else of the 2nd if statement - I am hoping that I only have to write the repeated contents once.
You can put your selectors in an array
var selectors = [#id_name_details_prefix_title', '#id_name_details_first_name' ...];
and then add/remove class
$(selectors.join(',')).addClass('kmw-disabled')
Break it up into functions that isolate what's going on.
{% if something %}
functionThathAddsClass();
{% else %}
{% if something_else %}
functionThatRemovesClass();
{% else %}
functionThathAddsClass();
{% endif %}
{% endif %}
You will run into the problem of creating two global functions in this case, but that's a different issue.
I like to make, what I personally call, CSS Guards.
A CSS Guard is basically just an object that has functions that pokes and prods at the DOM.
var NameDetailsGuard = {
functionThathAddsClass = function () {
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
},
functionThatRemovesClass = function () {
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
}
};
and you use it like this
NameDetailsGuard.functionThatAddsClass();
An added benefit to this is that if you expand on this concept you can start doing simpler DOM node caching within this object so that instead of querying for the selector everytime you'll retain a reference to it and manipulate that.
You can add some class to needed elements (in HTML markup) and select by that class.
For example, add category-zero and virtual-keyboard classes and use following:
{% if user.get_profile.subscription_category == '00' %}
$('.category-zero').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('.virtual-keyboard').removeClass('kmw-disabled');
{% else %}
$('.virtual-keyboard').addClass('kmw-disabled');
{% endif %}
{% endif %}
I'm doing the same as explained here: http://symfony.com/doc/current/cookbook/form/form_collections.html
But in my case I want to add new "tags" not manually with clicking on a link, but automatically. I give to my template an array with items and for each of this items I want to add a new form - the number of items should be equal to the number of forms.
If it's possible, I'd prefer a solution like this:
{% for i in items %}
{{ i.name }} {{ form_widget(form.tags[loop.index0].name) }}
{% endfor %}
But how to automatically create objects in the controller, too? It tells me that there is no obeject with index=1, and yes - there isn't, but isn't there a way to create them automatically and not need to create for example 10 empty objects of the same kind in my controller? :(
Another thing I was thinking was something like this:
{% for i in items %}
<ul class="orders" data-prototype="{{ form_widget(form.orders.vars.prototype)|e }}">
{{ i.name }} and here should be a field from the form, for example tag.name
</ul>
{% endfor %}
I suggest that the js given in the cookbook should be changed to do this, but I'm not good in js and my tries didn't do the job.
I tried putting this in the loop:
<script>
addTagForm(collectionHolder);
</script>
and this in a .js file:
var collectionHolder = $('ul.orders');
jQuery(document).ready(function() {
collectionHolder.data('index', collectionHolder.find(':input').length);
function addTagForm(collectionHolder) {
var prototype = collectionHolder.data('prototype');
var index = collectionHolder.data('index');
var newForm = prototype.replace(/__name__/g, index);
collectionHolder.data('index', index + 1);
var $newFormLi = $('<li></li>').append(newForm);
}
});
Assuming that your main class has addTag($tag) method, you can add different 'new' tags to it.
In class Task
public function addTag($tag){
$this->tags[]=$tag;
return $this;
}
In your Controller (assuming 10 tags here)
$task=new Task();
for($i=0;i<10;i++){
$task->addTag(new Tag());
}
$form->setData($task);
In your view
{% for tag in form.tags %}
<ul class="orders">
<li>{{ form_widget(tag.name) }}</li>
</ul>
{% endfor %}
If you don't need the manually click, you can remove the JavaScript part.