HTML and Javascript search bootstrap cards - javascript

Javascript returning : "Uncaught TypeError: Cannot read property 'innerText' of null" while typing on search form.
I have a page with some Bootstrap cards, and I want to filter the cards by name.
I have tried to get "card-title" element class to validate the search filter.
HTML code:
<div class="container">
<div class="row">
<div class="col-sm-4 mb-4">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for card name...">
</div>
</div>
<div class="row" id="myProducts">
<div class="col-md-4">
<div class="card">
<div class="card-header bg-dark d-sm-flex justify-content-sm-between align-items-sm-center">
<div class=" card-title">
<a href="#" style="color:white" class="display-inline- block" onmouseover="this.style.color='#00e6ac'" onmouseout="this.style.color='#fff'">
<strong>Card 1</strong>
</a>
</div>
</div>
<div class="card-body bg-light">
0000x01
</div>
<div class="card-footer bg-white d-flex justify-content-between">
<div>
<i class="icon-arrow-right5 mr-2"></i>Card number one
</div>
</div>
</div>
<div class="card">
<div class="card-header bg-dark d-sm-flex justify-content-sm-between align-items-sm-center">
<div class=" card-title">
<a href="#" style="color:white" class="display-inline- block" onmouseover="this.style.color='#00e6ac'" onmouseout="this.style.color='#fff'">
<strong>Card 2</strong>
</a>
</div>
</div>
<div class="card-body bg-light">
0000x02
</div>
<div class="card-footer bg-white d-flex justify-content-between">
<div>
<i class="icon-arrow-right5 mr-2"></i>Card number two
</div>
</div>
</div>
</div>
<!-- /transparent header, white footer -->
</div>
</div>
Javascript
function myFunction() {
var input, filter, cards, cardContainer, title, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
cardContainer = document.getElementById("myProducts");
cards = cardContainer.getElementsByClassName("card");
for (i = 0; i < cards.length; i++) {
title = cards[i].querySelector("card-title");
if (title.innerText.toUpperCase().indexOf(filter) > -1) {
cards[i].style.display = "";
} else {
cards[i].style.display = "none";
}
}
}
also testing on:
https://codepen.io/pratykus/pen/WNeJpyK
Every time I type on filter box I got incremented error:
(6) Uncaught TypeError: Cannot read property 'innerText' of null

When you use .querySelector you should specify the class or the element. In your case your element is the div and your class that you're trying to access is card-title, so change:
title = cards[i].querySelector("card-title");
to:
title = cards[i].querySelector(".card-title");

If you are passing a CSS class as the selector to querySelector(), then you have to append it with dot .
title = cards[i].querySelector(".card-title");
Make this change to fix the issue.

Related

JavaScript trying to append to HTML not working

I am trying to create a simple eCommerce website with HTML, CSS, and JavaScript. When a user adds an item to their cart I add that item to local storage and I want when the user goes to their cart, all the items in local storage are read and then displayed to the cart. Whenever I try to append I get this. Instead of displaying the HTML it displays a string of all the HTML?
function getCartItems() {
var items = JSON.parse(localStorage.getItem("cartItems"));
console.log({ items });
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
var cartRow = document.createElement("div");
// cartRow.classList.add("cart-row");
var cartItems = document.getElementsByClassName("cart-items")[0];
var cartRowContents = ` <li class="list-group-item d-flex flex-column">
<div class="row">
<div class="col col-lg-4">
<img
src="${items[i].image}"
alt="${items[i].name}"
class="d-block mx-auto"
/>
</div>
<div class="col col-lg-2 text-center">
<h5 class="mt-4 flex-wrap">${items[i].name}</h5>
<p>Size: 10.5</p>
<h2><span class="badge badge-danger">$189.99</span></h2>
</div>
<div class="col mt-4 text-center">
<p class="font-weight-bold">Quantity</p>
<input type="number" value="1" class="pl-2 w-50 rounded cart-quantity" />
<button
class="btn border border-none mx-5 mt-3 mt-lg-0 remove-item"
>
<i class="far fa-trash-alt"> </i>
</button>
</div>
</div>
</li>`;
cartRow.innerText = cartRowContents;
cartItems.append(cartRow);
}
}
Here is the code for my HTML
<!-- Cart -->
<div class="card m-5 border border-none mw-50">
<div class="card-header text-center text-white bg-primary">
Your Order
</div>
<ul class="list-group list-group-flush cart-items">
<li class="list-group-item d-flex flex-column">
<div class="row">
<div class="col col-lg-4">
<img
src="./images/products/air-max-270.jpg"
alt="Air Max 270"
class="d-block mx-auto"
/>
</div>
<div class="col col-lg-2 text-center">
<h5 class="mt-4 flex-wrap">Nike Air Max 270</h5>
<p>Size: 10.5</p>
<h2><span class="badge badge-danger">$189.99</span></h2>
</div>
<div class="col mt-4 text-center">
<p class="font-weight-bold">Quantity</p>
<input type="number" value="1" class="pl-2 w-50 rounded cart-quantity" />
<button
class="btn border border-none mx-5 mt-3 mt-lg-0 remove-item"
>
<i class="far fa-trash-alt"> </i>
</button>
</div>
</div>
</li>
</ul>
Call appendChild with innerHTML:
var cartItems = document.getElementsByClassName("cart-items")[0];
var cartRow = document.createElement("div");
cartRow.innerHTML = cartRowContents;
cartItems.append(cartRow);
Note: innerHTML is only destructive when used in combination with the += operator, as it causes a DOM refresh. It's all right to use it with createElement, as you're only changing the child's innerHTML, not the entire DOM. Reference
It seems you have confused Element.innerHTML with HTMLElement.innerText, as the latter sets your String to be the Node's actual text, not its HTML.
However, since it is discouraged to use Element.innerHTML for manipulating a Node's HTML, you should instead use Element.insertAdjacentHTML() instead.
This is because you are using innerText. You can use innerHtml instead but it's not recommended.
The way you are doing this, the only way you can pull it off is by using innerHTML like your last answer. However, if you want to do it the 'recommended' way, I would recommend using something called HTML DOM. You can recode all that you did simply by using the concept of creating elements and then appending them to each other and, finally, your cart. Here is the simple concept:
https://www.w3schools.com/js/js_htmldom.asp

Apply different styles to bootstrap card

I'm working with Angular 9 with a Bootstrap 4 card applying NGFOR to paint as many elements as come from the database.
I have the following array with different styles for that card and I would like them to be applied to each one in a random way.
public color_border = ["border-left-warning", "border-left-info", "border-left-primary"]
The card code is as follows: the div card border-left-info has to be changed. I have tried a new NGFOR but it duplicates everything.
<!-- Pending Requests Card Example -->
<div class="col-xl-3 col-md-6 mb-4" *ngFor="let data of miDataInterior.DatagreenhouseRecuperado; let i = index">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">{{data.medidas[0].sensor_type[0].name_comun}}</div>
<font SIZE=3> {{data.medidas[0].marca}} </font>
<font SIZE=3>({{data.medidas[0].recvTime | date:'dd-MM-yy h:mm:ss a'}})</font>
<div class="h5 mb-0 font-weight-bold text-gray-800">{{data.medidas[0].attrValue | number:'1.0-1'}} {{data.medidas[0].sensor_type[0].medida}}</div>
</div>
<div class="col-auto">
<i class="fas fa-chart-bar fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
How could I apply what is contained in the color_border variable in that div?
Error:
<!-- Pending Requests Card Example -->
<div class="col-xl-3 col-md-6 mb-4" *ngFor="let data of miDataInterior.DatagreenhouseRecuperado; let i = index">
<div *ngFor="let color_border of color_border" class="card {{color_border}} shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">{{data.medidas[0].sensor_type[0].name_comun}}</div>
<font SIZE=3> {{data.medidas[0].marca}} </font>
<font SIZE=3>({{data.medidas[0].recvTime | date:'dd-MM-yy h:mm:ss a'}})</font>
<div class="h5 mb-0 font-weight-bold text-gray-800">{{data.medidas[0].attrValue | number:'1.0-1'}} {{data.medidas[0].sensor_type[0].medida}}</div>
</div>
<div class="col-auto">
<i class="fas fa-chart-bar fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
Thanks for your help.
EDIT
I am testing directly on NGCLASS, the problem is that it only shows the style of the last element in the array. How can I fix this?
<div class="card shadow h-100 py-2" [ngClass]="['border-left-primary', 'border-left-info', 'border-left-warning']">
Alternate border
[ngClass]="color_border[i%3]"
A random you need make a function (you can not use Math inside the .html)
[ngClass]="getRandomColor()"
getRandomColor()
{
return this.color_border[Math.floor(Math.random()*this.color_border.length]
}
If you miDataInterior.DatagreenhouseRecuperado has a property "color" from 0 to 2 you can use
[ngClass]="color_border[data.color]"
NOTE there're severals ways to use [ngClass], see the docs
Try this..
<div *ngFor="let color_border of color_border" class="card shadow h-100 py-2 " [ngClass]="{{color_border}}">

Searching and filtering through list elements JS

In todolist i try to search my values so that i use indexOf!=-1 property ,when i console log everything works but i dont see that on screen strangely, i want to see only what i search.
html
<div class="container">
<div class="row">
<div class="col-md-5 mx-auto mt-5">
<div class="card p-4">
<h3 class="result-title">My Program</h3>
<input type="text" placeholder="Search" class="search"/>
<div class="card-body ">
<ul class="result-list">
<li class="result-item">Go to the Shop</li>
</ul>
</div>
</div>
<div class="card mt-5 p-5">
<h3> Add Here </h3>
<form>
<input type="text" class="addtext" placeholder="SOME "/>
<button class="addbutton">Add </button>
</form>
</div>
</div>
</div>
</div>
JS file
// ADDING ITEM //
document.querySelector(".addbutton").addEventListener("click",(event)=>{ event.preventDefault()
const text=document.querySelector(".addtext").value
const asd=document.createElement("li")
asd.classList.add("result-item") ;
asd.innerHTML=text
document.querySelector(".result-list").appendChild(asd)
document.querySelector(".addtext").value=""
} )
//SEARCH ITEM//
const search=document.querySelector(".search")
search.addEventListener("change",()=>{
const list=document.querySelectorAll(".result-item")
search.value.toLowerCase()
list.forEach(item=>{
if(item.innerHTML.toLowerCase().indexOf(search.value)!=-1) {item.style.display==="block"}else{;item.style.display==="none"}}) })
You need use =, not ===.
item.style.display="block"}else{;item.style.display="none"}
One equal sign changes the value, while two or three compare the value.

AngularJs - On ng-click all items get affected

I'm trying to change the scope when i click on the element but when i do that all the elements get's changed
What im trying to accomplish is when i click on one of the div, i want te color of the div to change to red. this part works fine. Then i also want to the scope to change when i click on one of the divs. What is happening here is that all the scopes are changing.
<div class="col-md-3 col-sm-6 mb-3" ng-repeat="student in stuRegister.students" ng-click="stuRegister.absneceChange($index, absence)">
<div id="myDIV{{$index}}" class="card text-white bg-success o-hidden h-100" data-index="{{$index}}">
<div class="card-body">
<div class="mr-5" >
<p>{{$index + 1}}. <strong>{{student.name}}</strong></p></div>
<div class="mr-5" data-ng-model-options="stuRegister.aData.role" ><strong ng-bind="absence">Status: {{absence[0]}}</strong></div>
</div>
<a class="card-footer text-white clearfix small z-1" href="#">
<span class="float-left">Indmeld fravær</span>
<span class="float-right">
<i class="fa fa-angle-right"></i>
</span>
</a>
</div>
</div>
Js:
$scope.absence = "Tilstede";
this.absneceChange = function(index, absence){
var element = document.getElementsByClassName("card");
$scope.absence = $scope.absence === "Tilstede" ? "Fravær" : "Tilstede";
element[index].classList.toggle("bg-danger");
element[index].classList.toggle("bg-warning");
}

javascript doesn't work in all elements of foreach MVC

i build a code for comments and replies of them.. i use a #foreachto show all elements in ViewBag which have a list of comments..
every thing works fine in post and get ..
but my problem it's when i try to make "submit"button of replies disable to prevent anyone from pressing it without typing..
so i use javascript but the code didn't work fine ..
first it work only with the last element of #foreach .. after i use the name as "class" instead of "id" it work for all elements
but the problem is .. if i typing in first reply input text for example .. the button didn't enable .. but if i typing at last reply input text .. all buttons enable ..
I want the code work for each reply .. only when some one typing in that input text ..
JavaScript
<script>
var $inputreply = $('.replies');
var $buttonreply = $('.replysubmit');
setInterval(function () {
if ($inputreply.val().length > 0) {
$buttonreply.prop('disabled', false);
}
else {
$buttonreply.prop('disabled', true);
}
}, 100);
</script>
View which have loop #foreachof comments and replies for each comment
<section class="comment-list">
#foreach (var item in ViewBag.CommentsList)
{
<article class="row">
<div class="col-md-10 col-sm-10">
<div class="panel panel-default arrow left">
<div class="panel-body">
<header class="text-left" style="direction:rtl;">
<time class="comment-date" datetime="16-12-2014 01:05"><i class="fa fa-clock-o"></i> #item.CommentDateTime</time>
</header>
<div class="comment-post">
<p>#item.Comment</p>
</div>
<p class="text-right"><a class="btn btn-default btn-sm replybtn"><i class="fa fa-reply"></i> reply</a></p>
</div>
</div>
<!--ReplyBox-->
#if (Request.IsAuthenticated)
{
using (Html.BeginForm("Reply", "Home", new { #id = #item.PostID, #commentId = #item.ID }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="input-group" style="direction:ltr;">
<input type="text" class="replies form-control" placeholder="" name="replies" />
<span class="input-group-btn">
<button class="replysubmit btn btn-primary" type="submit">Reply</button>
</span>
</div>
}
}
else
{
<div class="form-horizontal">
<div class="alert alert-danger replybox" style="display:none;">
<span>please login to reply</span>
</div>
</div>
}
#foreach (var subitem in ViewBag.Relies)
{
if (#subitem.CommentID == #item.ID)
{
<article class="row">
<div class="col-md-9 col-sm-9">
<div class="panel panel-default arrow left">
<div class="panel-heading left">Reply</div>
<div class="panel-body">
<header class="text-left">
<time class="comment-date" datetime="16-12-2014 01:05"><i class="fa fa-clock-o"></i> #subitem.ReplyDate</time>
</header>
<div class="comment-post">
<p>#subitem.CommentReply</p>
</div>
</div>
</div>
</div>
<div class="col-md-2 col-sm-2 col-md-offset-1 col-sm-offset-0 hidden-xs">
<figure class="thumbnail">
<img class="img-responsive" src="http://www.keita-gaming.com/assets/profile/default-avatar-c5d8ec086224cb6fc4e395f4ba3018c2.jpg" />
<figcaption class="text-center">#subitem.UserName</figcaption>
</figure>
</div>
</article>
}
}
</div>
<div class="col-md-2 col-sm-2 hidden-xs">
<figure class="thumbnail">
<img class="img-responsive" src="http://www.keita-gaming.com/assets/profile/default-avatar-c5d8ec086224cb6fc4e395f4ba3018c2.jpg" />
<figcaption class="text-center">#item.userName</figcaption>
</figure>
</div>
</article>
<br />
}
</section>
The selector $('.replysubmit') returns all the items with that css class, hence updating the disabled property of all those elements, not just the one closest to the input element.
You should use a relative selector to get the submit button inside the form where the reply input element is.
jQuery closest() and find() methods will be handy
This should work
$(function () {
$('.replysubmit').prop('disabled', true); // Disable all buttons when page loads
// On the keyup event, disable or enable the buttons based on input
$(".replies").keyup(function() {
if ($(this).val().length > 0) {
$(this).closest("form").find(".replysubmit").prop('disabled', false);
} else {
$(this).closest("form").find(".replysubmit").prop('disabled', true);
}
});
});

Categories