I have a list of cards displayed via a for loop. On click I want to toggle some text.
It works fine for the top card, but when I click the card below, it toggles the first card.
This is the case even though i've given the cards different id's used in the javascript toggle function.
Any ideas about what i'm doing wrong?
<!-- HTML -->
{% for card in cards %}
<div class="card mb-3">
<div class="card-header">
<img class = "float:left mr-2 mt-1 small-profile-picture" src ="{{ card.creator.profile.image.url }}" >
<a class="mb-4 float-up" > {{ card.creator }}</a>
<small> <p class=mt-2> {{ card.date }} </p> </small>
</div> <!-- Card Header ender -->
<!-- Here we have the questions and answers -->
<div onclick="myFunction()" style="cursor: pointer;">
<div class="card-body mt-4">
<h5 class="card-title"> <a class="article-title">{{ card.question }}</a></h5>
<p id="myDIV{{card.card_id}}"> Click to see Answer </p>
<!-- <p class="card-text"> {{ card.answer}} </p> -->
</div> <!-- Card body ender -->
</div>
<!--Javascript -->
<script type="text/javascript">
function myFunction() {
var x = document.getElementById("myDIV{{card.card_id}}");
if (x.innerHTML === "Click to see Answer") {
x.innerHTML = "{{card.answer}}";
} else {
x.innerHTML = "Click to see Answer";
}
}
</script>
{% endfor %}
Thanks for reading
There's a lot of things I would do differently here if I'm honest, but to keep the solution as close to your code as possible, I'd suggest the following. Remove the <script> from within your loop - you're redefining the function every time it loops. This is unnecessary and will probably cause a bunch of undesired effects.
Separate the JavaScript and pass myFunction arguments, rather than hard-coding strings into the function.
This is untested, but should point you in the right direction.
<script type="text/javascript">
function myFunction(id, answer) {
// note the template literal syntax below,
// this is different to the handlebars provided by django.
let x = document.getElementById(`card-${id}`);
if (x.innerHTML === "Click to see Answer") {
x.innerHTML = answer;
} else {
x.innerHTML = "Click to see Answer";
}
}
</script>
{% for card in cards %}
<div class="card mb-3">
<div class="card-header">
<img class = "float:left mr-2 mt-1 small-profile-picture" src="{{ card.creator.profile.image.url }}" >
<a class="mb-4 float-up"> {{ card.creator }}</a>
<small> <p class=mt-2> {{ card.date }} </p> </small>
</div>
<div onclick="myFunction({{ card.card_id }}, {{ card.answer }})" style="cursor: pointer;">
<div class="card-body mt-4">
<h5 class="card-title"> <a class="article-title">{{ card.question }}</a></h5>
<p id="card-{{ card.card_id }}"> Click to see Answer </p>
</div>
</div>
</div>
{% endfor %}
I changed a bit the questions and answers block:
function myFunction(ele) {
ele.querySelector('.card-body.mt-4 .card-text').classList.toggle('d-none');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<div onclick="myFunction(this)" style="cursor: pointer;">
<div class="card-body mt-4">
<h5 class="card-title"> <a class="article-title">{{ card.question }}</a></h5>
<p id="useless...."> Click to see Answer </p>
<!--- removed comment from the next line -->
<p class="card-text d-none"> This is the answer ....{{ card.answer}} </p>
</div> <!-- Card body ender -->
</div>
Related
so I'm building this online learning website, and I have a catalog of all courses where you can search for courses which titles or description contain the input in the search bar. I used bootstrap cards to make the catalog. It's working well, but on desktop I get empty spaces in place of the cards which are hidden, and the results show with big empty spaces between them is there were courses in between etc. No issue on mobile, all results show up vertically one after another. Is there a way to go around that? thanks!
Picture to see the "empty spaces"
JS code:
$('#live_search').on('keyup', function() {
let input = $(this).val();
$('.card').hide();
$('.card').filter(function() {
return new RegExp(input, 'i').test($(this).text())
}).show();
});
Cards:
<div class="search">
<form>
<label for="live_search">Rechercher une formation :</label>
<input type="text" id="live_search" size="30" class="form-control" placeholder="Rechercher une formation" />
</form>
</div>
<br>
<div class="container px-5 mb-3">
<div class="row">
{% for formation in formations %}
<div class="col-md-4">
<div class="card">
<img class="card-img-top" src="{{ vich_uploader_asset(formation, 'imageFile') }}" alt="{{ formation.imageName }}">
<div class="card-body">
<h5 class="card-title">{{ formation.title }}</h5>
<p class="card-text">{{ formation.description }}</p>
<a class="small btn btn-success custom-btn rounded-pill px-3" href="{{path('app_formations_see', {'id' : formation.id })}}" role="button">voir</a>
<span class="small">par {{ formation.user.firstname }} {{ formation.user.lastname }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
You're hiding the card but keeping the col-md-4 div. You can merge the col-md-4 and card divs.
Just hide the col-md-4 div by introducing a "wrapper" class (or whatever you want to call it)
JS Code
$('#live_search').on('keyup', function() {
let input = $(this).val();
$('.wrapper').hide();
$('.wrapper').filter(function() {
return new RegExp(input, 'i').test($(this).text())
}).show();
});
Cards
<div class="search">
<form>
<label for="live_search">Rechercher une formation :</label>
<input type="text" id="live_search" size="30" class="form-control" placeholder="Rechercher une formation" />
</form>
</div>
<br>
<div class="container px-5 mb-3">
<div class="row">
{% for formation in formations %}
<div class="col-md-4 wrapper">
<div class="card">
<img class="card-img-top" src="{{ vich_uploader_asset(formation, 'imageFile') }}" alt="{{ formation.imageName }}">
<div class="card-body">
<h5 class="card-title">{{ formation.title }}</h5>
<p class="card-text">{{ formation.description }}</p>
<a class="small btn btn-success custom-btn rounded-pill px-3" href="{{path('app_formations_see', {'id' : formation.id })}}" role="button">voir</a>
<span class="small">par {{ formation.user.firstname }} {{ formation.user.lastname }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
I have a group of bootstrap cards. When i click a button in a card always retrieve information from thirst card. document.querySelectorAll('.fa-bookmark') works properly but document.querySelector(".card-title") inside click listener retrieve the first card information. I want information from which card i click.
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll(".fa-bookmark").forEach(bookmark => {
bookmark.onclick = function(event) {
alert(document.querySelector(".card-title").innerHTML);
}
})
})
<div class="container">
<div class="row">
{% for article in news.articles %}
<div class="col-sm">
<div class="card" style="width: 18rem;">
<img class="card-img-top" src="{{article.urlToImage}}" alt="{{article.source.name}}">
<div class="card-body">
<i class="far fa-bookmark"></i>
<i class="fas fa-bookmark" id="dl_bookmark"></i>
<h5 class="card-title">{{article.title}}</h5>
<p class="card-text">{{article.description|truncatechars:100}}</p>
Read
</div>
</div>
</div>
{% endfor %}
</div>
</div>
fix JavaScript #LoadMore button to load 5 items per page - Django
i want show 5 item per once then user click on LoadMore button then it will load more 5 items
how to do that with js ?
html code :
{% for mobile in mobileforhome %}
<div class="card-deck">
<div class="card mb-3" style="max-width: 800px;">
<div class="row no-gutters">
<div class="col-md-4">
<img style="height:100%;width:100%;border-radius:6.5px;" src="{{ mobile.get_image }}" class="rounded float-right" alt="...">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title" id="primary_site_pages_app_name_control"> <b>{{ mobile.name }}</b></h5>
<p class="card-text" id="font_control_for_all_pages">{{ mobile.app_contect|truncatechars_html:153|safe}}</p>
</div>
<div class="card-footer">
<small class="text-muted" id="date_post_control">{{ mobile.post_date}}</small>
<small class="firstsmall"><a class="bg-orange" href="{% url 'mobile' %}" id="tag_name_control">هواتف</a></small>
</div>
</div>
</div>
</div>
</div>
<hr>
{% endfor %}
<!-- show more button -->
<div class="text-center mt-4">
<a role="presentation" type="button" class="btn btn-secondary btn-lg loadMore" style="width:40%;color:white">Show More</a>
</div>
<!-- script controll the games ( show 6 game per page ) -->
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script>
const thumbnails = $(".card-deck .card mb-3");
let visibleThumbnails = 0;
function showThumbnailsUntil(index) {
for (var i = visibleThumbnails; i <= index; i++) {
if (i < thumbnails.length) {
$(thumbnails[i]).addClass('visible');
visibleThumbnails++;
} else {
break;
}
}
}
showThumbnailsUntil(2);
$(".loadMore").on("click",function(){
showThumbnailsUntil(visibleThumbnails + 2)
if(visibleThumbnails === thumbnails.length)
{
$(".loadMore").fadeOut(); //this will hide
//button when length is 0
}
})
</script>
<style>
.card-deck {
display: none;
}
.card-deck.visible {
display: block;
}
</style>
<!-- end script -->
this is my code but it don't work why ? (it's show button and you can press on it but it's do nothing ! it's show all items not 5 )
This is my code, when i click edit button, the "msg" div opens and retrieves the corresponding message. But it displays message only in first div "msg" and when i click second or third edit button its shows only first row div. "msg" does not display the second or third div "msg".
{% for datas in data %}
<div class="row">
<div class="col-md-12">
<div class="card shadow-lg">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h5 class="card-title"><i class="fa fa-user-circle" aria-hidden="true"></i>
{{datas.user_id|capfirst}}</h5>
</div>
<div class=" col-md-6 text-right" >
{% if request.user.id == datas.user_id_id %}
<button id="edit" value="{{datas.post}}" onclick="edit(this)">Edit</button>
{% endif %}
</div>
</div>
<div id="msg">
<hr>
{{datas.post}}
<hr>
</div>
<div class="row">
<div class="col-md-4"><i class="fa fa-thumbs-up"></i></div>
<div class="col-md-4"></div>
<div class="col-md-4 text-right">{{datas.post_date}}</div>
</div>
</div>
</div>
</div>
</div>
<br>
<script type="text/javascript">
function edit(id)
{
var body = id.value;
document.getElementById("msg").innerHTML = '<form action="" method="POST">{% csrf_token %}<div class="form-group"><textarea class="form-control" name="edit_post" rows="3">'+body+'</textarea><br> <button class="btn btn-primary" type="submit">POST</button></div><div></form>';
}
</script>
{% endfor %}
HTML id are should be unique, better use classes. If you have multiple element with the same id document.getElementById("msg") will only return the first match.
But you can solve this problem by going to the parent element ".card-body" of the clicked element (which is button, I see you passed "this") then use querySelector to find the "msg" id inside card-body.
function edit(elem)
{
var parentcard = elem.closest(".card-body")
parentcard.querySelector("#msg").innerHTML = "content here"
}
where elem is the passed 'this' parameter
At the moment I am loading a list of products but I want to restrict it to the first 10 so that I can then use the Load More button to show the rest a few at a time. Unfortunately it seems to be loading all of the products instead of a select few.
<div id="products-grid" class="ui grid stackable three column">
#foreach($products as $product)
<div class="eight wide tablet five wide computer column" key="{{ $product->id }}">
<div class="ui fluid card single-product">
<a href="{{ url('brands/'.$product->brandslug.'/'.$product->slug)}}" class="image">
#if($product->product_img != 'null')
<img src="{{ url('/images/'.$product->product_img)}}" title="{{ $product->name }}" alt="{{ $product->name }}">
#else
#endif
</a>
<div class="product-title content">
<a href="{{ url('brands/'.$product->brandslug.'/'.$product->slug)}}" class="title">
<h5 class="fix-title">{{ $product->name }}</h5>
<div class="fix-subtitle">From {{ $product->brandname }}</div>
</a>
</div>
<div class="content">
<a href="{{ url('/brands/'.$product->brandslug.'/'.$product->slug)}}">
<button class="grey ui button centered fluid">View Product</button>
</a>
</div>
</div>
</div>
#endforeach
</div>
Above is the product grid I have that displays the relative products.
if(count($products)>10)
<div class="loadmore" id="load_more">
<button class="ui inverted button">
Load More
</button>
</div>
#endif
This basically displays the button if there are more than 10 products on a particular page.
#section('script')
<script type="application/javascript">
$(document).ready(function () {
$("#products-grid").slice(0, 8).show();
if ($("#products-grid:hidden").length != 0) {
$("#load_more").show();
}
$("#load_more").on('click', function (e) {
e.preventDefault();
$("#products-grid:hidden").slice(0, 6).slideDown();
if ($("#products-grid:hidden").length == 0) {
$("#load_more").fadeOut('slow');
}
});
});
</script>
#endsection
This is the script that is meant to hide some of the displayed products so that when I click Load More, it displays the others 6 or 7 at a time until there are no products left to show. This partially works as the button fades out when there are no products left to show (as it should do). The issue is it loads everything so I'm not sure why the javascript code isn't working as it should do?