i have this code:
{% for review in reviews %}
<div>
{{ review.content }}
by {{ review.username }}
- timeDifference("{{ review.date_submitted }}")
</div>
{% endfor %}
on the 5th line is a js function timeDifference that will return time difference in text, I want to insert js function there, how do I do that?
this is the solution that worked for me, inspired by Raja Simons' answer and How to add onload event to a div element?:
<div id="review{{review.id}}">
{{ review.content }} by {{ review.username }}
-
<p id="timeDifferenceElement{{ review.id }}"></p>
<script type="text/javascript">
timeDifferenceForDate( '{{ review.id }}', '{{ review.date_posted }}' );
</script>
Execute Js function like that is not possible. And what possible is during onload time execute the javascript function and do DOM manipulation.
In Html
<-- In for loop -->
<div onload="timeDifference( {{ review.id }}, {{ review.date_submitted }} );">
<p id="timeDifferenceElement{{ review.id }}"></p>
</div>
In Javascript
function timeDifference(id, date_submitted) {
const timeDifferenceElement = document.getElementById("timeDifferenceElement" + id)
// Do calculation
---
timeDifferenceElement.innerHTML = "something from the calculation"
}
Related
I have several posts each of them composed of three parts : a title, a username/date and a body. What I want to do is to show the body when I click on either the title or the username/date and hide it if I click on it again. What I've done so far works but not as expected because when I have two or more posts, it only shows the body of the last post even if I click on another post than the last one. So my goal is only to show the hidden text body corresponding to the post I'm clicking on. Here is my code:
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Test page{% endblock %}</h1>
<a class="action" href="{{ url_for('main_page.create') }}">New</a>
{% endblock %}
{% block content %}
{% for post in posts %}
<article class="post">
<header>
<script language="JavaScript">
function showhide(newpost)
{var div = document.getElementById(newpost);
if (div.style.display !== "block")
{div.style.display = "block";}
else {div.style.display = "none";}}
</script>
<div onclick="showhide('newpost')">
<h1>{{ post['title'] }}</h1>
<div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%d-%m-%Y') }}</div>
</div>
</header>
<div id="newpost">
<p class="body">{{ post['body'] }}</p>
</div>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
Of course I looked for a solution as much as I could but I'm kind of stuck plus I'm a complete beginner in HTML/JS/CSS. And one last thing, I'm currently using Python's framework Flask. Thank you by advance.
You need to give each of your posts a unique id for your approach to work.
Change your code to
<div id="{{post_id}}">
<p class="body">{{ post['body'] }}</p
</div>
where post_id is that post's unique id e.g. its id in the database you are using that you pass to the template in your view. Then, change the call to the onclick event handler to
<div onclick="showhide('{{post_id}}')">
If you don't have a unique id you can also use the for loop's index: replace all post_id instances above with loop.index. See Jinja's for loop docs for more information.
So I have the following file structure:
plugins/myname/pluginname/components/pluginname/default.htm
plugins/myname/pluginname/components/PluginName.php
default.htm acts as the partial of the component.
and I have the following JS API
setInterval(function(){
$.request('onEverySecond', {
update: {'#default.htm':'#rate-marquee'},
complete: function() {
console.log('Finished!');
}
})
}, 1000);
onEverySecond is a function in PluginName.php that updates a variable called fx thrown to default.htm.
At the front end the partial default.htm seems to be updated, but it refreshes the whole partial which is not what I want, it causes the marquee to replay again and again and only be able to show the first few piece of contents.
All I wanted is that the AJAX will update only the variable fx where the data is updated.
How can I achieve that?
EDIT 1:
Here is the partial markup:
{% set fx = __SELF__.fx %}
<marquee id="rate-marquee" name="rate-marquee" onmouseover="this.stop();" onmouseout="this.start();">
<ul>
{% for item in fx %}
<li>
{{ item.Item | trim('u')}}: {{ item.BID }} {% if item.Revalue == 0 %} <div class="arrow-up"></div> {% else %} <div class="arrow-down"></div> {% endif %}
</li>
{% endfor %}
</ul>
</marquee>
Additionally, here is the code in PluginName.php
public function onRun()
{
$this->addJs('/plugins/SoyeggWebDevelopment/fxmarquee/assets/js/default.js');
$this->updateFX();
}
public function onEverySecond()
{
$this->updateFX();
}
public $fx;
So updateFX() works perfectly well too.
Here problem seems you are replacing whole marquee it causes to re-render it.
To solve this we can just update portion inside marquee
setInterval(function(){
$.request('onEverySecond', {
complete: function() {
console.log('Finished!');
}
})
}, 1000);
We don't do anything special here just a simple ajax call
to update portion of marquee we need to assign id to it and we define internal partial
<marquee id="rate-marquee"
name="rate-marquee"
onmouseover="this.stop();" onmouseout="this.start();">
<ul id='rate-marquee-inner'> <!-- <= here -->
{% partial __SELF__ ~ '::_marquee_inner' %}
</ul>
</marquee>
_marquee_inner.htm partila markup
{% set fx = __SELF__.fx %}
{% for item in fx %}
<li>
{{ item.Item | trim('u')}}: {{ item.BID }} {% if item.Revalue == 0 %} <div class="arrow-up"></div> {% else %} <div class="arrow-down"></div> {% endif %}
</li>
{% endfor %}
and to update that portion we just need to return markup array
function onEverySecond() {
$this->updateFX();
return ['#rate-marquee-inner' => $this->renderPartial('_marquee_inner.htm')];
}
this will just push new updated markup to given id #rate-marquee-inner so now it will just update inner portion of marquee and marquee will not re-render.
if any doubt please comment.
here I am passing {{id}} to hide_show(...) javascript function
{% for stock in part_temp.part_stock_set.all %}
{% with id="list"|concatenate:stock.id %}
<div id="{{ id }}">
{{ stock.entry_date}}
</div>
<button type="button" onclick="hide_show({{ id }})">edit</button>
<br>
{{ id }}
here above the {% endwith %} {{ id }} is displaying correctly but the hide_show function in not called but it is called when just {{ stock.id }} is passed to it.
the concatenate filter just concatenates and returns a string.
<script type="text/javascript">
function hide_show(temp) {
document.getElementById(temp).style.display='none';
window.alert(temp);
}
</script>
Problem seems to be with the quotes. if {{ id }} returns a string, then you don't have to put quotes here
<div id="{{ id }}">
Simply replace it with:
<div id={{ id }}>
If id is an integer or if the above doesn't work, then you have to put quotes here as well as in the argument while calling the hide_show function.
I've been trying all day long to include this liquid code inside javascript with no luck so far..
I'm simply trying to update a div with the cart data to show the image and name, this is what I've got.
$('.openCart').click(function(e)
{
$.ajax({
type: 'POST',
url: '/cart/add.js',
data: data,
dataType: 'json',
success: function()
{
{% capture content %}{% include 'addItemToCartDetails' %}{% endcapture %}
var content = {{ content | json }};
$("._second").html(content);
}
});
});
Overall the following code doesn't work(simply because of the for loop, and I have no clue how to get around this..): If I remove the for loop then the code retrieves the divs and everything, besides the item data since the loop isn't working.
This is the addItemToCartDetails.liquid,
{% for item in cart.items %}
<div class="_second_1">
<a href="{{ item.url | widivin: collections.all }}" class="cart-image">
<img width="320" src="{{ item | img_url: '700x700' }}" alt="{{ item.title | escape }}">
</a>
</div>
<div class="_second_2"><h3>Product Name</h3>{{ item.product.title }}</div>
<div class="_second_3"><h3>Remove Product</h3><span class="clearCart">Remove</span></div>
<div class="_second_4"><h3>Quantity</h3><input class="quantity" type="input" name="updates[]" id="updates_{{ item.id }}" value="{{ item.quantity }}" min="0" data-id="{{ item.id }}" title="If you'd like another subscription please checkout separately" alt="If you'd like another subscription please checkout separately" disabled></div>
<div class="_second_5">
<h3>Total Price</h3>
<div class="totalDetails">Total: {{ item.line_price | plus: 0 | money }} / month</div>
</div>
<div class="_third">
<input type="submit" name="checkout" value="PROCEED TO CHECKOUT">
</div>
{% endfor %}
You are trying to use Liquid when you should be using Javascript
All of the Liquid processing happens on the backend to construct an HTML file that gets passed to the browser. Once the HTML page has been passed to the user's browser, Javascript can be used to manipulate the document and make this appear/disappear/change.
Practically, this means that your {% for item in cart.items %} in addItemToCartDetails.liquid will be rendered once, before page load, and never again afterwards. No matter how many items are added to the cart, the results of that snippet will only ever be current as of page load.
You should be using the Javascript variables instead
Shopify passes the line item object representing the most recently-added product to your success callback function. Your code should look something like this:
$('.openCart').click(function(e)
{
$.ajax({
type: 'POST',
url: '/cart/add.js',
data: data,
dataType: 'json',
success: function(line_item)
{
var content = '<h3>You added a ' + line_item.title + '!</h3>' +
'<p> We appreciate that you want to give us ' + Shopify.formatMoney(line_item.line_price, {{ shop.money_format }}) + '!</p>' +
'<p>That is very nice of you! Cheers!</p>';
// Note: Not every theme has a Shopify.formatMoney function. If you are inside an asset file, you won't have access to {{ shop.money_format }} - you'll have to save that to a global javascript variable in your theme.liquid and then reference that javascript variable in its place instead.
$("._second").html(content);
}
});
});
If you're curious about what all you can access in the response object, add a console.log(line_item) to the beginning of your success function to print the object to your browser's console. (In most browsers you can right-click any element on the page and select 'Inspect Element' to bring up your developer tools. There should be a tab called 'Console' where the logs get printed to, and once your information is there you should be able to click on the object to expand its contents.)
In your first snippet, pass cart.items as the variable items to the template:
{% include 'addItemToCartDetails', items: cart.items %}
In the file addItemToCartDetails.liquid template, modify the for loop statement accordingly:
{% for item in items %}
In your case, you can put this {% capture content %}{% include 'addItemToCartDetails' %}{% endcapture %} in your liquid code somewhere in your HTML probably hidden and append it to the element where you want it to appear like so.
success: function()
{
var content = $("#addItemToCartDetails-wrapper").html();
$("._second").html(content);
}
Something like that. Hope that helps!
I study Django and want to use ajax. Read some examples, but have problem.
I need to show all posts by click on link with name site.
view:
def archive(request, page_number=1):
posts = BlogPost.objects.all()
current_page = Paginator(posts, 3)
if request.is_ajax():
t = loader.get_template("archive_ajax.html")
else:
t = loader.get_template("archive.html")
c = Context({'posts': current_page.page(page_number),
'username': auth.get_user(request).username})
return HttpResponse(t.render(c))
base.html:
<h1><a class="refresh" >mysite.example.com</a></h1> (I need click it and update posts )
<div class="content">
<div>
{% block content %}
{% endblock %}
</div>
</div>
archive.html:
{% extends "base.html" %}
{% block content %}
{% for post in posts %}
{% include "archive_ajax.html" %}
{% endfor %}
{% endblock %}
archive_ajax.html (problem not here, I mean firstly I need to solve problem which higher ):
<h2> {{ post.title }} </h2>
<p> author: {{ post.author.username }}</p>
<p> {{ post.timestamp | date:"l, F jS, Y" }} </p>
<p> {{ post.body }} </p>
In base.html includ jquery: <script src="/static/jquery-1.11.1.min.js" type="application/javascript"></script>
And I try to write code
$(document).ready(function(){
$(".refresh").click(function(){
console.log('clicked');
$(".content").load("/blog/");
});
});
when I click on link I see it on the place where might be posts:
{"content": "
\n
\u0430\u0432\u0442\u043e\u0440:
\n
\n
\n", "status": 200, "statusText": "OK"}
In command line I see "GET /blog/ HTTP/1.1" 200 151
I try another way and write:
$(document).ready(function(){
$(".refresh").click(function(){
$.ajax({
type: "GET",
url: "/blog/",
success : function(newdata) {
$('.content').html(newdata);
}
});
});
});
And now I can see nothing in place where might be posts.
In command line I see "GET /blog/ HTTP/1.1" 200 151`
In view I add print
if request.is_ajax():
t = loader.get_template("archive_ajax.html")
print('it is query'`)
and in command line I see message - it's query, for ajax and js.
I use python 2.7.3, Django 1.6.5 and jquery 1.11.1.min.
Thank you all! I find my mistake, it was in ajax and in template archive_ajax.html. It's my inattention I think. In template I forgot to add loop for {{posts}}. now it's:
{% for post in posts %}
<h2> {{ post.title }} </h2>
<p>автор: {{ post.author.username }}</p>
<p> {{ post.timestamp | date:"l, F jS, Y" }} </p>
<p> {{ post.body }} </p>
{% endfor %}
And in ajax I correct it:
$('.content').html(newdata.content);
It is not a good practice to write:
<h2> {{ post.title }} </h2>
Take a look at the {% url %} template tag.
Edit - Disclaimer: the current user has not enough rate to comment. That's why this apparently answer-less answer is posted here.