Dynamically generate hyperlink with keypress (without submit) in Flask App - javascript

https://jsfiddle.net/mjcyezh0/
I'm creating a Flask webapp for work and on the main page, I ask my users if they're an interviewer at the company. If they select YES, I prompt them for their ID (i.e. 290).
In another space on the page, I've used jinja2 to programmatically loop through a dictionary of questions and links to generate a series of questions, hyperlinks and inputs for my user; this will allow them to answer questions and have helpful links that are customized for the current time/date.
One of the hyperlinks sends the user to a custom search in our interviewer platform, but the only way to direct them to the right place is to have that ID within the URL, (i.e: website.com/###/interviewers/.....)
Questions re: Javascript
Is there anyway that using .keypress and (no onclick/button submission), I can dynamically populate the content WITHIN the href of that particular link? (post-completion is fine)
If yes, how can I fit this into my jinja2 {% for %} loop to address the ONE specific entry? (row 12, when `x['tech_key'] == 'int') [That is, do I want to add a particular ID/CLASS to it in order to run the js code?]
Code attached for my for-loop:
1 <div class="col-md-8">
2
3 {% for k,v in inps['sheet'].items() %}
4 {% for x in v %}
5 {% if x['question'] is not number %}
6
7 <div class="{{x['tech_key']}}">
8 <hr class="thicker">
9 <b>{{x['question']}}</b>
10 <button class="add_form_field" data-key="{{x['tech_key']}}"><b>+</b></button><br>
11 {% for i in ['1', '2', '3'] if x['link'+i] is not number%}
12** {{x['text'+i]}}{{ " | " if not loop.last }}
13 {% endfor %}<br>
14
15 {% if x['subtext'] is not number%}
16 <i><p style="font-size: 12px;overflow:auto">{{x['subtext']}}</p></i>
17 {% endif %}
18 <div><input type="text" name="{{x['tech_key']}}1" size="80px"></div>
19 </div>
20 {% endif %}
21 {% endfor %}
22 {% endfor %}
23 </div>

You need the build the link URL after retrieving the interviewer id:
First give your elements an id:
<input type="text" id="form_interviewer_id" name="interviewer_id" value="" >
<a id="linkAnchor" href="https://example.com/interviewer/0?start_date=2020-07-01">palp</a>
Then you can access them via JavaScript:
window.onload = function() {
var textField = document.getElementById("form_interviewer_id");
textField.onkeyup = function(evt) {
evt = evt || window.event;
if (evt.keyCode == 13 || this.value.length == 2) { // Updated
var linkAnchor = document.getElementById("linkAnchor");
linkAnchor.href = getLink(textField.value);
}
};
};
function getLink(id) {
return "https://example.com/" + id + "/0?start_date=2020-07-01";
}
Updated Fiddle: https://jsfiddle.net/63onu9dm/ [Updated]

Related

Created "Buy X, Get Y Free" Script, How To Prevent Script From Running If Customer Removes Y?

In our store, I wrote a script that if a customer buys 1 out of 13 total valid items, another item (y) would be automatically added to their cart and be made free. The issue I am running into is that every time the customer removes that free item from their cart, the cart-template page reloads and reruns my script, which automatically adds that free item back to the customers cart.
My goal is that although we automate the processing of adding the "free item" to the cart, the customer still has the ability to remove it if they chose, and even increase its quantity, though only one will remain free.
Attached is my JS that executes the above code :
{% assign liveCode = "yes" %}
{% assign bootmodeList =
"3932518121587,6631396442197,3957106442355,2017147617395,1658735951987,1561223331955,1561223430259,4810721853525,1658760495219,1561223397491,4698621739093,1658762166387,4760306810965" | split : ',' %}
{% assign product_to_add_auto = all_products['test-test-test-enet-cable-bootmod3-flashing-and-f-series-and-g-series-coding-cable'] %}
{% assign start = "2022-10-18" | date: '%s' %}
{% assign end = "2022-10-19" | date: '%s' %}
{% assign today = "now" | date: '%s' %}
{% if start <= today and today <= end %}
{% unless cart.item_count == 0 or product_to_add_auto.empty? or product_to_add_auto.variants.first.available == false %}
{% assign variant_id = product_to_add_auto.variants.first.id %}
{% if liveCode == "yes" %}
{% if product_to_add_auto.available == true %}
{% assign isProduct = false %}
{% for item in cart.items %}
{% assign product_id = item.product_id | append:"" %}
{% if bootmodeList contains product_id %}
{% assign isProduct = true %}
{% endif %}
{% endfor %}
{% if isProduct == true %}
{{ product_to_add_auto | json }}
<script>
(function(jquery) {
let cartItems = {{ cart.items | json }},
qtyInTheCart = 0,
cartUpdates = {};
console.log(cartItems);
for (let i = 0; i < cartItems.length; i++) {
if (cartItems[i].id === {{ variant_id }}) {
qtyInTheCart = cartItems[i].quantity;
break;
// this checks the cart to prevent double addition of wifi adapter
}
}
if ((cartItems.length === 1) && (qtyInTheCart > 0)) {
cartUpdates = {
{{ variant_id }}: 0
}
// if wifi adapter is already in cart by itself without bootmode, remove it.
} else if ((cartItems.length >= 1) && (qtyInTheCart !== 1)) {
cartUpdates = {
{{ variant_id }}: 1
}
// adds wifi adapter to cart if bootmode is in cart and theres not one already
} else {
return;
// if none are true, code doesnt run "catch all"
}
// http response object
const params = {
type: 'POST',
url: '/cart/update.js',
data: {
updates: cartUpdates
},
dataType: 'json',
success: function(stuff) {
window.location.href = '/cart'; // reloads to cart on successful post request
}
};
jquery.ajax(params);
// fires ajax request using jquery
})(jQuery);
</script>
{% endif %}
{% endif %}
{% endif %}
{% endunless %}
{% endif %}
My first attempt at solving this involved creating a unique ID on the "remove" button of the shopping cart and adding an event listener to it with a ".preventDefault()" function attached to it, but it prevented the entire code from working and removed the ability to auto add the free item.
It is pretty simple. If you added the free item to the cart in the first place, you used a Javascript call to do that. So set your localStorage to have a key:value pair of something like "free": true.
Anytime you go to run your add this free thing to the cart, check if that key exists. If it does not, add the free thing. If it does exist, it means you already added a freebie to the cart, so don't do that again. If the customer chose to remove it, so be it, now it won't be re-added. You can then remove that key if you want on the way to checkout, or whatever... leave it.
Taking from the answer posted above, here is what I was able to come up :
const params = {
type: 'POST',
url: '/cart/update.js',
data: {
updates: cartUpdates
},
dataType: 'json',
success: function(stuff) {
window.location.href = '/cart'; // reloads to cart on successful post request
}
};
if(sessionStorage.getItem('itemInCart') === null ) {
jquery.ajax(params);
}
sessionStorage.setItem('itemInCart', 'true');

Using Javascript to change text Content of a button

Hey guys I'm creating a social media messaging app and right now I'm on the basics of creating a button to follow people.
When you click the button, it should change the button from saying "Follow" to "UnFollow". Then the counter for Followers should go up by 1.
So far this is my code and it's not doing anything. I'm not getting any errors but it's also not doing anything at all.
Can someone figure out what I'm doing wrong? Thanks
network.js:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('followButton').addEventListener('click', () => follow_user());
});
function follow_user() {
const element = document.getElementById('followButton');
element.value = "Un-Follow";
const element2 = document.getElementById('followers');
element2.textContent += 1;
}
profile.html :
{% extends "network/layout.html" %}
{% block body %}
<h2>{{user.username}}'s Profile</h2>
<p id="followers">Followers: {{user.followers}}</p>
<p>Follows: {{user.follows}}</p>
{% for newquery in newqueries reversed %}
<div class="newpost"><p>{{ newquery.body }}</p><p>By: {{ newquery.username }} on: {{ newquery.timestamp }} Likes: {{ newquery.likes }}</p></div>
{% endfor %}
<input type="button" value="Follow" id="followButton">
{% endblock %}
Your first problem is your follower count does not have an ID. You are trying to target it with #followers, but it only has a class .followers.
Your second problem is button inputs don't display textContent. They display their value.
const element = document.getElementById('followButton');
element.value = "Un-Follow";
Try something like this: const element = document.getElementById("followButton").value="Un-Button Follow" i think the value should be Button in between the un and follow i.e un-follow, Note(change it to suit your code)
Check this article here: https://www.permadi.com/tutorial/jsInnerHTMLDOM/index.html

Can't process ajax call on my page because Django request.is_ajax returns True when page is intially loaded

I have a page that makes ajax calls, and my view checks if the call is ajax with .is_ajax function. However, when the page is initially loaded (for example if I stop running the server and then restart it) the is_ajax function seems to return True, which causes a MultiValueDictKeyError at /alltext, because the request does not contain the key "alltext", which contains the data from my other ajax call.
The page is a e-commerce product page, and the product has different variants (i.e. size and color), and when the user chooses variants from a dropdown menu (i.e. Large, Blue), it makes an ajax call to the backend to retrieve the price of this specific variant from the database.
Here is my code:
views.py
def product_info(request):
if request.method == "GET" and not request.is_ajax: # this is supposed to be loaded on page load
return render(request, "product_info.html")
elif request.is_ajax and request.method == "GET":
print(request.is_ajax)
'''When a user chooses a product variant on the page, this makes an ajax call
to retrieve the price of this combination'''
print("request was ajax")
combinations = request.GET["alltext"]
combinations_list = combinations.split(";")
product = Product.objects.all().latest("id")
var_names = Variation.objects.filter(product=product)
corresponding_values = []
for i in range(len(combinations_list)):
# finding this variant in database
var_name = var_names[i]
var_values = VariationValue.objects.filter(variation_name=var_name)
for val_obj in var_values:
val = val_obj.value
if val == combinations_list[i]:
corresponding_values.append(val_obj)
found_price = None
for i in range(len(corresponding_values)):
val = corresponding_values[i]
if i == 0:
combo_query = VariationCombination.objects.filter(variation_value=val)
else:
combo_query = combo_query.filter(variation_value=val)
price = combo_query[0].price
return HttpResponse("You chose: " + combinations + "price: " + price)
And here is the relevant part of the product_info page - the forms where the user chooses the variants and the script that sends the variants to the backend:
product_info.html
<form class="variations-form">
{% for name in variation_names %}
<div class="form-group">
<label class="btn-label">{{ name.variation_name }}:</label>
<!--<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
<span class="selection"></span><span class="caret"></span>
</button>-->
<select name="variation{{ forloop.counter }}" class="form-control variations" id="variation{{ forloop.counter }}">
<option value="" selected disabled>{{ name.variation_name }}</option>
{% for key, value_list in variation_values.items %}
{% if key == name.variation_name %}
{% for value in value_list %}
<option value="{{ value }}">{{ value }}</option>
{% endfor %}
{% endif %}
{% endfor %}
</select>
</div>
<br>
{% endfor %}
</form>
Script tag with ajax call
<script>
$(document).ready(function () {
$('.form-control').change(function(){
if ($('#variation1').val()) {
var valueFrom = $('.variations option:selected').map(function () {
return $(this).val();
}).get();
var alltext = valueFrom.join(";")
$('#chosen-options').html(alltext).show('fast');
$.ajax(
{
type:"GET",
data:{
'action':'options_chosen',
alltext: alltext
},
success: function( data )
{
$('#chosen-options').html(data).show('fast');
}
});
};
});
});
</script>
Still not entirely sure what was wrong but I fixed it! At first, the page was setup so that it loads the template "homepage.html" at first, and then when you click on a product it opens in the same page, by loading the template "product_info.html". So I just changed it so that the product_info opens up on a new page when you click a product (and added the new page to urls.py), and now it works!

Use a javascript array to display specific HTML divs

Using django I have a HTML page with a table containing checkboxes:
{% for o in obj %}
<input class='germ_ids' name='{{o.id}}'>
{% endfor %}
<script>
var elements = document.getElementsByClassName("germ_ids");
var ids = [];
for(var i=0; i<elements.length; i++) {
ids.push(elements[i].name);
}
</script>
This has given me an array of specific 'germ ids'. These relate to other django objects I have:
the same .html page:
{% for k, v in add_state_dict.items %}
<div class='{{k.id}}_statement'>
<p>{{v}}</p>
</div>
{% endfor %}
<div class='all_germ'>
<p>{{additional_statement}}</p>
</div>
What I want to achieve is a statement for each germ_id when their checkbox is checked. However when more than one boxes are checked, it makes a concat statement called additional_statement in the 'all_germ' class.
I have hard coded it in in a JSFiddle http://jsfiddle.net/sDsCM/1037/
However I want to use the elements in the array to do this to account for different array values.
You should not be using class names with IDs but instead use class names that categorize your checkboxes. As example I'll be using .checkbox-plus-info. Also, use a data attribute to find the associated statement (unless you can render them inside one div):
{% for o in obj %}
<input class='germ_ids checkbox-plus-info' name='{{o.id}}'
data-info-tag="info-{{o.id}}">
{% endfor %}
{% for k, v in add_state_dict.items %}
<div id='{{k.id}}_statement' class="info info-{{k.obj_id}}">
<p>{{v}}</p>
</div>
{% endfor %}
In the above, k of course needs to contain a reference to the object (its PK/ID). You should have that information in your view and add it to the context. You haven't posted your view/context code but the business logic should mostly be ready while you create the template context, so prepare as much as you can there.
In your JS:
$(".checkbox-plus-info").click(function() {
$(".info").hide(); // hide all
stmtElId = $(this).target.data("info-tag");
$("#" + stmtElId).show();
// check whether something has to be shown when several checkboxes are checked
// e.g. count whether all checkboxes are checked, or other logic
});

Shopify run for loop again after clicking Check-Out button

I'd like to run this for-loop again after clicking the checkout button, to check if the quantity is 2 oder less to set check_nike = true.
is this possible without reloading the side again after the customer set the product quantity on 2?
{% for item in cart.items %}
{% if item.title contains 'nike' %}
{% if item.quantity > 2 %}
{% assign check_nike = false %}
{% endif %}
{% endif %}
{% endfor %}
I have although implemented this in my theme.liquid
$('body').on('click', '[name="checkout"], [name="goto_pp"], [name="goto_gc"]', function() {
if ($('#agree').is(':checked') && {{check_nike}} == true ) {
$(this).submit();
}
else {
if({{check_nike}} == false){
alert("You can't only order two Nike products");
}
else{
document.getElementById("centerbox1").className += " forgottocheck";
}
return false;
}
});
</script>
Thanks :)
You can't use liquid code {{ check_nike }} in a JavaScript for any client side activity. Rather you can try checking the cart.js file of Shopify.
Whenever a product is added to cart use GET as shown in - https://docs.shopify.com/themes/development/getting-started/using-ajax-api#get-cart to see if you specific condition matches.
Going further you can also use localStorage or cookies to reduce the number of GET calls by storing specific cart information locally.

Categories