Alpine js - $dispatch from another component -> this.$dispatch is not a function - javascript

First sorry for my english!
Im trying to create add to cart ajax button in Shopify with Alpine js and JS Vanilla, but when click in the button the console says this.$dispatch(the dispatchs come from another liquid files) is not a function, i think is something about the scope of the function, im new on alpine and also i didnt find doc about this. I let my code:
<div class="product--information px-4 md:px-0 md:sticky"
x-data="{
addToCart() {
let formData = new FormData(this.$refs.product_form);
fetch('/cart/add.js', {
method: 'POST',
body: formData
})
.then(response => {
return response.json();
})
.then(response => {
this.$dispatch('cart-updated');
this.$dispatch('toggle-cart');
})
.catch((error) => {
console.error('Error:', error);
});
}
}"
>
{% form 'product', product, id: 'product-form', novalidate: 'novalidate', x-ref: 'product_form' %}
<div class="flex md:w-1/2">
<button type="button" #click="addToCart()" class="flex-1 p-4 uppercase bg-black text-white text-center" {% if
selected_variant.variant.available==false %} disabled {% endif %}>
{% if selected_variant.variant.available == false %}
Sold Out
{% else %}
Add to cart
{% endif %}
</button>
</div>

There are several bugs, even without seeing the full code, I could add the following lines of code, but it would be very helpful to add the full code of your "template-product.liquid" file.
Add below product--information this code:
{%- assign product_form_id = 'product-form-' | append: section.id -%}
like this:
<div class="product--information px-4 md:px-0 md:sticky"
{%- assign product_form_id = 'product-form-' | append: section.id -%}
and then in the end of code, change:
{% form 'product', product, id: 'product-form', novalidate: 'novalidate', x-ref: 'product_form' %}
to this:
{%- form 'product', product, id: product_form_id, class: 'form', novalidate: 'novalidate', x-ref: 'product_form' -%}
Let me know if it works :)

Related

How to use v-on:click to change multiple content - Vuejs and Liquid [duplicate]

This question already has answers here:
onclick multiple elements in vue js
(2 answers)
Closed 1 year ago.
I would like to change text and image when I click on a button, I had tried this but I get stuck and I don't know how to use it to change multiple elements,
{% for variant in product.variants %}
<label for="variant_{{- variant.id }}">{{ variant.title }} - <img src="{{ variant.image | img_url: '100x100' }}" v-on:click="changeMessage('{{ variant.price | money_with_currency }}')"></label>
<input type="radio" {% if forloop.first %}checked{% endif %} class="variant_id" id="variant_{{- variant.id }}" name="productVariants" value="{{ variant.id }}"/>
<div class="variant_price d-none">{{ variant.price | money_with_currency }}</div>
<div class="variant_sku d-none">{{ variant.sku }}</div>
<div class="variant_img d-none">{{ variant.image | img_url: master }}</div>
{% endfor %}
{% raw %}{{ price }}{% endraw %}
{% raw %}{{ image }}{% endraw %}
Current look on the store
The price is now showing by default I have to click the radio button to show the price, I want it to be shown by default,
This is how it looks like after I click on the radio button
export default {
data () {
return {
price: document.getElementsByClassName('variant_price').innerHTML,
sku: document.getElementsByClassName('variant_sku').innerHTML,
img: document.getElementsByClassName('variant_img').innerHTML,
}
},
methods: {
changeMessage(message) {
this.message = message
}
},
}
I want when I click on the radio button it gives me the price and image, my skills on JS is so bad, please I need help 🙏🙏🙏
Try to use mounted() hook to set your defaults.
export default {
data () {
return {
price: document.getElementsByClassName('variant_price').innerHTML,
sku: document.getElementsByClassName('variant_sku').innerHTML,
img: document.getElementsByClassName('variant_img').innerHTML,
}
},
mounted(){
//set default here, like this
this.changeMessage(message);
}
methods: {
changeMessage(message) {
this.message = message
}
},
}
Also, could you elaborate it a little bit more so that I can help you in this regard
In order to change another element using v-on:click on a button you should add to these elements a parameter ref="nameOfRef" and then select them in the method you called on the v-on:click like: this.$refs.nameOfRef
Example:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="vue-app">
<div ref="div">Hello world</div>
<button type="button" v-on:click="hideElements()">Hide!</button>
<button type="button" v-on:click="showElements()">Show!</button>
</main>
<script>
var app = new Vue({
el: "#vue-app",
methods: {
hideElements: function () {
this.$refs.div.style.display = "none";
},
showElements: function () {
this.$refs.div.style.display = "inherit";
}
}
});
</script>

Assign color to text in website based on ID in database

In my forums website, I want to assign a certain color to each role. For example the admin color is blue, so the username of this admin is always blue. In my database, I'm using MySQL, I have a role table that assigns an ID for each role and a users table linked to the role table.
How can I assign the color I want to the role ID that I want?
Note: I'm using Django for my back-end work
Thank you.
This is what I've tried so far.
<div class="username"> <a id= "usercolor" style="color: white; cursor: pointer;"
onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }}
</a>
<script>
{% if instance.author.Role.RoleName == "Admin" %}
document.getElementById("usercolor").style.color="blue";
{% endif %}
</script>
<br>
</div>
I assigned a default color white to the username inside the forum and gave it an id. I then took the RoleName column in my userrole table from the database and using if statement and document.getElementById I tried to make it that only the admin color is blue. This only changed the color of the first admin as shown in the image here
Javascript lets you assign keys and values in arbitrary pairs. For instance, you could set your role/color combos with a structure like this:
const roleColors = {
admin: "goldenrod",
moderator: "purple",
notableTroll: "olive",
}
This would let you get the color associated with a role, such as admin with
const adminColor = roleColors.admin;
or, assuming you had a user object with a role property shaped like
{
username: "JimNaysium",
role: "admin"
}
you could get the user's role with
const adminColor = roleColors[user.role];
If you want to have this in a function, instead of a direct lookup, you could do something like:
function getColorByRole(role) {
const roleColors = {
admin: "goldenrod",
moderator: "purple",
troll: "olive",
};
return roleColors[role];
}
Good luck and happy coding.
To answer my own post even though delayed. I used Django instance and an if condition for each role ID as follows:
{% for instance in item %}
<div class="post">
<div class="body">
<div class="authors">
<div class="row">
<img class="account-info-sub2" style="border-radius:50%" src="{{ instance.author.user_thumbnail.url }}" alt="error">
<div class="username"> <a class="{% if instance.author.Role.RoleName == 'User' %} shimmeruser {% elif instance.author.Role.RoleName == 'Admin' %} shimmeradmin {% elif instance.author.Role.RoleName == 'Forum Moderator' %} shimmermoderator {% elif instance.author.Role.RoleName == 'Customer Service' %} shimmerservice {% endif %}" style="cursor:pointer;" onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }} </a>
<br>
</div>
<div class="rolemob">
<div class="account-info-sub2">{{ instance.author.Role.RoleName }} </div>
</div>
</div>
As you can see in the if condition, if the author of the post has a rolename of Admin his colour should be the one assigned in the "shimmeradmin" CSS. "author", "Role" and "RoleName" are all from the database. Ignore the div tags, they're not wrong I just didn't copy the whole code obviously.
To summarize. What you need to do understand is this line of code:
<div class="username"> <a class="{% if instance.author.Role.RoleName == 'User' %} shimmeruser {% elif instance.author.Role.RoleName == 'Admin' %} shimmeradmin {% elif instance.author.Role.RoleName == 'Forum Moderator' %} shimmermoderator {% elif instance.author.Role.RoleName == 'Customer Service' %} shimmerservice {% endif %}" style="cursor:pointer;" onclick="openmodal( {{ instance.author.id }})"> {{ instance.author.Username }} </a>

Ajax like button not showing increment in count or else

I wanted to add like heart button with like count. I want to use ajax for changing likes count and color change. but when I tried to do that it won't work.
HTML
<div id="posts">
{% for post in page_obj %}
<div><a >{{ post.userp }}</a></div>
<div>{{ post.content }}</div>
<div>{{ post.timestamp }}</div>
<div id="post_name">
{% if request.user in post.userl.all %}
<a class="likeu" style="cursor: pointer"><span id="{{ post.id }}" class="likeu1" style="font-size:24px;color:red">♥</span></a>
{% else %}
<a class="likeu" style="cursor: pointer"><span id="{{ post.id }}" class="likeu1" style="font-size:24px;color:grey">♥</span></a>
{% endif %}
<p id="{{ post.id }}l">{{ post.userl.all.count }}</p>
</div>
<hr>
{% endfor %}
</div>
and JAVASCRIPT
document.querySelectorAll('.likeu1').forEach(element => element.addEventListener('click', change_like));
function change_like(){
post_id = this.id
console.log(post_id)
fetch('/likes', {
method: 'POST',
body: JSON.stringify({
post_id : post_id,
})
})
.then(response => response.json())
.then(result => {
value = result["is_liked"];
console.log(value);
console.log(this);
if (value == 'true'){
this.style.color = 'red';
console.log('red');
}
else{
this.style.color = 'grey';
console.log('grey');
}
})
}
It is updating when I refresh but I want it without refresh.
I don't know what I am doing wrong. please help!

How do I close each instance of the same div class one a time using Javascript

What I'm trying to do is very straightforward: close every instance of a div each time the close button is clicked. What I'm getting instead is only the first clicked-on instance closes but the remaining ones can't.
I must say I come from Python and I'm not very familiar with Javascript. I think there is someway using ID instead of class? Here is my html (with Jinja) code for dynamically creating the objects I would want to close when clicked on:
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages%}
<div class="notification {{ category }} is-bold">
<button class="delete"></button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
And here is my Javascript code:
// notification remover
document.addEventListener('DOMContentLoaded', () => {
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
$notification = $delete.parentNode;
$delete.addEventListener('click', () => {
$notification.parentNode.removeChild($notification);
});
});
});
Example of generated html:
<div class="notification is-info is-bold">
<button class="delete"></button>
<div class="notification is-info is-bold">
<button class="delete"></button>
<div class="notification is-info is-bold">
<button class="delete"></button>
Try this instead:
document.addEventListener('DOMContentLoaded', () => {
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
$delete.addEventListener('click', (event) => {
event.target.parentNode.remove();
});
});
});
The problem with your code is that you are setting $notification with the last one, so when the eventListener triggers $notification is always the last.

Django 1.10 - Ajax - order of operations?

I am using Ajax with Django 1.10 to implement a like functionality ( a user likes an image posted by another user) on my website. I have the following code :
The views file :
#ajax_required
#login_required
#require_POST
def image_like(request):
image_id = request.POST.get('id')
action = request.POST.get('action')
if image_id and action:
try:
image = Image.objects.get(id=image_id)
if action == 'like':
image.users_like.add(request.user)
else:
image.users_like.remove(request.user)
return JsonResponse({'status':'ok'})
except:
pass
return JsonResponse({'status':'ko'})
def image_detail(request, id, slug):
image = get_object_or_404(Image, id=id, slug=slug)
return render(request,
'images/image/detail.html',
{'section': 'images',
'image': image})
In base.html :
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src=" http://cdn.jsdelivr.net/jquery.cookie/1.4.1/jquery.cookie.min.js "></script>
<script>
var csrftoken = $.cookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$(document).ready(function(){
{% block domready %}
{% endblock %}
});
</script>
And finnaly in the detail.html :
{% extends "base.html" %}
{% block title %}{{ image.title }}{% endblock %}
{% block content %}
...
{% with total_likes=image.users_like.count users_like=image.users_like.all %}
<div class="image-info">
<div>
<span class="count">
<span class="total">{{ total_likes }}</span>
like{{ total_likes|pluralize }}
</span>
<a href="#" data-id="{{ image.id }}" data-action="{% if request.user in users_like %}un{% endif %}like" class="like button">
{% if request.user not in users_like %}
Like
{% else %}
Unlike
{% endif %}
</a>
</div>
{{ image.description|linebreaks }}
</div>
<p> Image liked by :</p>
<div class="image-likes">
{% for user in image.users_like.all %}
<div>
<p>{{ user.last_name }}</p>
</div>
{% empty %}
Nobody likes this image yet.
{% endfor %}
</div>
{% endwith %}
{% endblock %}
{% block domready %}
$('a.like').click(function(e){
e.preventDefault();
$.post('{% url "images:like" %}',
{
id: $(this).data('id'),
action: $(this).data('action')
},
function(data){
if (data['status'] == 'ok')
{
var previous_action = $('a.like').data('action');
// toggle data-action
$('a.like').data('action', previous_action == 'like' ?
'unlike' : 'like');
// toggle link text
$('a.like').text(previous_action == 'like' ? 'Unlike' :
'Like');// update total likes
var previous_likes = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'like' ?
previous_likes + 1 : previous_likes - 1);
}
}
);
});
{% endblock %}
While I mostly understand the code itself, I need help understanding in what orders the requests, the callback functions and everything else is executed ... something like : ,users clicks the like button, that information is passed to the server , it is being manipulated, data-base modified , sent back, the page changes ...
Tell me if any extra code ( models, urls etc. ) is needed. Could't post everything.

Categories

Resources