Trying to filter out elements Javascript - javascript

I'm trying to filter certain films based on selections from the below dropdowns.
<select id="filmDropdown">
<option value="0">All Films</option>
<option value="1">Film 1</option>
<option value="2">Film 2</option>
<option value="3">Film 3</option>
</select>
<select id="dateDropdown">
<option value="All">All Dates</option>
<option value="Mon">Mon</option>
<option value="Tues">Tues</option>
<option value="Wed">Wed</option>
<option value="Thurs">Thurs</option>
<option value="Fri">Fri</option>
<option value="Sat">Sat</option>
<option value="Sun">Sun</option>
</select>
<input type="button" value="Search" onclick="getSelectedValues()" />
And here's the html for the films to be selected.
<div id="allFilms">
<div id="1" class="filmTag">
Film 1
<p>
Mon
</p>
<ul>
<li>12:00</li>
<li>16:00</li>
</ul>
<p>
Wed
</p>
<ul>
<li>19:00</li>
</ul>
</div>
<div id="2" class="filmTag">
Film 2
<p>
Tues
</p>
<ul>
<li>12:00</li>
<li>16:00</li>
<li>18:00</li>
</ul>
</div>
<div id="3" class="filmTag">
Film 3
<p>
Wed
</p>
<ul>
<li>12:00</li>
<li>16:00</li>
</ul>
</div>
</div>
I'm trying to use Javascript to hide all the films other than the one selected. This is what I'm doing but it doesn't seem to pick up the selected film and will just hide everything.
<script>
function getSelectedValues() {
var f = document.getElementById("filmDropdown");
var selectedFilm = f.value;
if (selectedFilm !== 0) {
var filmClass = document.getElementsByClassName("filmTag");
for (var i = 0; i < filmClass.length; i++) {
if (filmClass.id === selectedFilm) {
filmClass[i].style.display = "block";
}
else {
filmClass[i].style.display = "none";
}
}
}
}
</script>

If you are developing your own application you might want to render the html based on a structure, like React does, for example. So you have a state where you can also represent your filters. Doing the other way around using selectors is not convenient and very confusing, you might incur in race conditions too, it doesn't worth it.
If you are doing it as external script in a page you didn't develop, something like a Grease Monkey script, then it's a different story. But if you can control how your page is rendered, you might want to change your approach.

For a quick and dirty fix, this line:
if (filmClass.id === selectedFilm) {
needs to be:
if (filmClass[i].id === selectedFilm) {

It's generally not a good idea to use inline event handlers
Here's an alternative using event delegation css selectors and data attributes to filter the elements. Dropped the button and applied a change handler and simplified html.
document.addEventListener("change", showSelected);
function showSelected(evt) {
if (/dropdown/i.test(evt.target.id)) {
const selectValues = {
films: document.querySelector("#filmDropdown").value,
weekday: document.querySelector("#dateDropdown").value
};
// (re)show all initially
document.querySelectorAll("[data-films], [data-weekday]")
.forEach(elem => elem.classList.remove("hide"));
// nothing to do (selected all/all)
if (selectValues.films < 1 && selectValues.weekday === "All") {
return true
}
// css queryselectors based on values
// i.e. all elements *not* in current selection
const films = selectValues.films !== "0" ?
`[data-films]:not([data-films='Film ${selectValues.films}'])` : '';
const weekdays = selectValues.weekday !== "All" ?
`${films ? `, ` : ''}[data-weekday]:not([data-weekday='${
selectValues.weekday}'])` : '';
//hide all not selected elements
document.querySelectorAll(`${films}${weekdays}`)
.forEach(elem => elem.classList.add("hide"));
}
}
body {
font: normal 12px/15px verdana, arial;
margin: 2rem;
}
.hide {
display: none;
}
ul[data-films] {
margin-left: -1rem;
}
li[data-weekday]:before {
content: attr(data-weekday)' ';
}
ul[data-films]:before {
content: attr(data-films);
position: relative;
background-color: green;
color: white;
padding: 1px 3px;
margin-left: -1rem;
margin-bottom: 1rem;
bottom: 4px;
font-weight: bold;
}
<select id="filmDropdown">
<option value="0">All Films</option>
<option value="1">Film 1</option>
<option value="2">Film 2</option>
<option value="3">Film 3</option>
</select>
<select id="dateDropdown">
<option value="All">All Days</option>
<option value="Mon">Monday</option>
<option value="Tues">Tuesday</option>
<option value="Wed">Wednesday</option>
<option value="Thurs">Thursday</option>
<option value="Fri">Friday</option>
<option value="Sat">Saturday</option>
<option value="Sun">Sunday</option>
</select>
<ul data-films="Film 1">
<li data-weekday="Sun">14:00</li>
<li data-weekday="Sun">16:00</li>
<li data-weekday="Sun">20:00</li>
<li data-weekday="Mon">16:00</li>
<li data-weekday="Mon">12:00</li>
<li data-weekday="Mon">16:00</li>
</ul>
<ul data-films="Film 2">
<li data-weekday="Tues">12:00</li>
<li data-weekday="Tues">16:00</li>
<li data-weekday="Wed">12:00</li>
<li data-weekday="Wed">16:00</li>
<li data-weekday="Sun">18:00</li>
<li data-weekday="Sun">20:00</li>
</ul>
<ul data-films="Film 3">
<li data-weekday="Tues">10:00</li>
<li data-weekday="Tues">14:00</li>
<li data-weekday="Wed">12:00</li>
<li data-weekday="Wed">16:00</li>
<li data-weekday="Fri">12:00</li>
<li data-weekday="Fri">16:00</li>
<li data-weekday="Sat">10:00</li>
<li data-weekday="Sat">16:00</li>
<li data-weekday="Sat">17:00</li>
</ul>

Related

JQuery - How to pass active class between desktop and mobile menu?

I have a tab menu which shows/hides blog-posts based by category. On the mobile version of my application, I have a select dropdown instead of the tab-menu. My issue is, that when I hit a tab, let's say "nature", this tab gets the "active" class - now when I switch to the mobile version, the "nature" tab is of course not "active" - how can I solve this?
Here is my JS-code:
The tab menu:
var $btns = $(".tab").on("click", function(e) {
let clickedTab = $(e.currentTarget).attr("data-tab-id");
if (clickedTab == "all") {
$(".blog-posts > div").fadeIn(450);
} else {
var $el = $("." + clickedTab).fadeIn(450);
$(".blog-posts > div")
.not($el)
.hide();
}
$btns.removeClass("active");
$(this).addClass("active");
});
And the Select dropdown:
$(".blog-tab-select").change(function() {
var selectedCategory = $(this).val();
if (selectedCategory == "all") {
$(".blog-posts > div").fadeIn(450);
} else {
$(".blog-posts .card").removeClass("active");
var $el = $("." + selectedCategory).fadeIn(450);
$(".blog-posts > div")
.not($el)
.hide();
}
});
UPDATE
Here is what my HTMl looks like:
<div class="blog-tabs d-none d-md-block">
<ul>
<li data-tab-id="all" class="tab all active">All</li>
#foreach ($blog_categories as $category)
<li data-tab-id="{{ strtolower($category->name) }}" class="tab {{ strtolower($category->name) }}">{{ $category->name }}</li>
#endforeach
</ul>
</div>
<div class="mobile-select d-md-none">
<select class="custom-select blog-tab-select w-50 float-right" id="blogTabSelect" name="blogTabSelect">
<option value="all">All</option>
#foreach ($blog_categories as $category)
<option data-tab-id="{{ strtolower($category->name) }}" value="{{ strtolower($category->name) }}">{{ $category->name }}</option>
#endforeach
</select>
</div>
Do I need some kind of "state" or "eventHandler"? Please help
Without seeing any HTML, the simplest (yet not the best ofc) would be to not duplicate your logic, but instead to trigger the <select>'s 'change' event - on tabs click:
const $sel = $('#blogTabSelect');
const $tab = $('[data-tab]');
const $cat = $('[data-cat]');
// Select does all the job
$sel.on("change", function(e) {
const val = this.value;
const $tabTarget = $(`[data-tab="${val}"]`);
const $catTarget = $(`[data-cat="${val}"]`);
$tab.not($tabTarget).removeClass('active');
$cat.not($catTarget).removeClass('active');
if(val === 'all') {
$cat.addClass('active');
} else {
$catTarget.addClass('active');
}
$tabTarget.addClass('active');
});
// LI just triggers SELECT's value and change event
$tab.on('click', function() {
$sel.val($(this).data('tab')).trigger('change');
});
[data-tab] {
background: transparent;
}
[data-tab].active {
background: #0bf;
}
[data-cat] {
visibility: hidden;
opacity: 0;
transition: 0.3s;
}
[data-cat].active {
visibility: visible;
opacity: 1;
}
<div class="blog-tabs d-none d-md-block">
<ul>
<li data-tab="all" class="active">All</li>
<li data-tab="cat">cat</li>
<li data-tab="dog">dog</li>
</ul>
</div>
<div class="mobile-select d-md-none">
<select id="blogTabSelect" class="custom-select blog-tab-select w-50 float-right">
<option value="all" selected>All</option>
<option value="cat">cat</option>
<option value="dog">dog</option>
</select>
</div>
<div class="blog-posts">
<div data-cat="cat" class="active">cat 1...</div>
<div data-cat="dog" class="active">dog...</div>
<div data-cat="cat" class="active">cat 2...</div>
</div>
<script src="//code.jquery.com/jquery-3.3.1.min.js"></script>

Cannot get the Selected Value from Materialize dropdown with React JS

I have this Materialize DropDown
<ul id="dropdown1" className="dropdown-content">
<li>
<a href="#!">
one
</a>
</li>
<li>
two
</li>
<li className="divider" tabIndex="-1"></li>
<li>
three
</li>
<li>
<a href="#!">
<i className="material-icons">view_module</i>four
</a>
</li>
<li>
<a href="#!">
<i className="material-icons">cloud</i>five
</a>
</li>
</ul>
and I have declared it as follows :-
componentDidMount() {
let dropdowns = document.querySelectorAll('.dropdown-trigger');
let options = {
inDuration: 300,
outDuration: 300,
hover: true, // Activate on hover
coverTrigger: false, // Displays dropdown below the button
};
M.Dropdown.init(dropdowns, options);
var instance = M.Dropdown.getInstance(dropdowns);
}
which displays fine, however I cannot manage to get the selected value.
I tried the following JQuery:-
$(document).ready(function(){
$('dropdown1').formSelect();
});
but I am getting a type error :-
TypeError: jquery__WEBPACK_IMPORTED_MODULE_6___default(...)(...).formSelect is not a function
Any help will be very much appreciated!
Thanks
I think one should use <Select> in case of a form to select from a list of options. So, you can initialize the Materialize components in componentDidMount() lifecycle method.
I attached onChange event listener on <Select> so that we can track the value and save it in our state. I also gave the defaultValue property so that a person knows in form what he has to choose, for example, Choose a country.
CodeSandbox - Working Demo (Select in React)
Select Component
import React, { Component } from "react";
import M from "materialize-css";
import "materialize-css/dist/css/materialize.min.css";
class Select extends Component {
constructor() {
super();
this.state = {
selectVal: null
};
}
componentDidMount() {
M.FormSelect.init(this.FormSelect);
}
handleChange = event => {
this.setState({
[event.target.name]: event.target.value
});
};
render() {
console.log(this.state.selectVal);
return (
<div className="input-field col s12">
<select
ref={FormSelect => {
this.FormSelect = FormSelect;
}}
name="selectVal"
onChange={this.handleChange}
defaultValue="0"
>
<option value="0" disabled>
Choose your option
</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
<label>Materialize Select</label>
</div>
);
}
}
export default Select;

Angular filter with ng-repeat not yet populated

I have filter options such as dropdown which act as filters for displayed content.
Said content is called from a DB, and take a few ms to get displayed. during those few ms, I have lot of error linked to the filtering system. does someone knows how to keep them quiet?
HTML markup
<div class="user-content py-4 px-5">
<ul class="nav justify-content-center pb-3" id="filters">
<li class="nav-item dropdown">
<select class="form-control" id="continent" ng-model="filter_continent">
<option value="">continent</option>
<option ng-repeat="con in continents" value="{{con}}">{{con}}</option>
</select>
</li>
<li class="nav-item dropdown">
<select class="form-control" id="category" ng-model="filter_cat">
<option value="">catégorie</option>
<option value="experience">Experience</option>
<option value="explore">Explore</option>
<option value="globe">Globe</option>
<option value="sleep">Sleep</option>
<option value="taste">Taste</option>
</select>
</li>
</ul>
<div ng-show="tipson" class="tips-widget text-center mb-5"
ng-repeat="item in userTips | filter:{category:filter_cat,continent:filter_continent}"
id="{{item._id}}"
style="background-image: url('{{item.cover}}');"
data-id="{{item._id}}"
ng-mouseenter="placeHover(item._id, item.lat)"
ng-click="show_tips(item._id)">
<div class="background"></div>
<p class="location"><span>{{item.country}}</span>, {{item.city}}</p>
<h3>{{item.name}}</h3>
</div>
</div>
and the errors I get. As soon as the ng-repeat source array is populated, errors stop.
Error: [filter:notarray] http://errors.angularjs.org/1.4.9/filter/notarray?p0=%7B%7D
EDIT
here is the instance code
//USER TIPS
$scope.userTips = {};
$scope.user_tips = function(id){
Tips.getByAuthorId(id)
.success(function(data) {
$scope.userTips = data;
});
}
Before you fetch the data from db, please check what userTips is initialized to. If it is not initialized, initialize it to an empty array.

Make first value in dropdown bold in angular js

I have a dropdown where I need to make first value in the dropdown to be bold.Dropdown code is as follows.
<div class="col-xs-3">
<select-box id="ad-version-select" options="curItem.stats.version" model="state.version" initial="All" change="watchvalue()" ng-disabled="state.partialDisable"></select-box>
</div>
<select class="form-control" ng-model="model" ng-change="change()">
<option ng-if="initial.length" ng-bind="initial" value=""></option>
<option ng-repeat="option in options" value="{{getValue()}}" ng-selected="model==getValue()" ng-bind="getTitleVariable()"></option>
</select>
I tried like
<style>
div.col-xs-3>div:first-child {
font-weight: bold;
}
</style>
but didn't worked. I am not getting any idea how to make only the first value bold. I can't use jquery. Can someone help me with this?
There need to be an alteration done in your css selector. You should select the first child of the option to make it bold.
option:first-child
{
font-weight: bold;
}
Here is the sample Fiddle
Hope this helps.
-Help :)
You can use ng-options with ng-class:
<select ng-model="Blah">
<option ng-repeat="person in persons" ng-class="{red: person.id == 1}" ng-selected="{Blah == person.Name}">{{person.Name}}</option>
</select>
app.controller('AppController',
[
'$scope',
function($scope) {
$scope.persons = [
{id: 1, Name:'John',Eligible:true},
{id: 2,Name:'Mark',Eligible:true},
{id: 3,Name:'Sam',Eligible:false},
{id: 4, Name:'Edward',Eligible:false},
{id: 5, Name:'Michael',Eligible:true}
];
$scope.Blah = 'Sam';
}
]);
Here is the Plunker
#Help's solution should work.
But not all browsers support styles in <select><option>. Maybe you need to build the component by yourself, something like this:
<div class="select">
<div class="selected" ng-bind="current.title"></div>
<div class="options">
<div class="option" ng-repeat="option in options" value="{{option.value}}" ng-bind="option.title" ng-click="current=option"></div>
</div>
</div>
.option:first-child {font-weight: bold;}
You'll need to add some more scripts and styles to make it work like a natural <select>.

Highlight Corresponding Names With Javascript

I have a list of names to display in a browser:
Alan, Ben, Cindy, Dan, Ellen, Fred.
I'd like the user to be able to select male or female.
Then I'd like the name(s) of people who are that gender to change colors, or become highlighted.
Is there a way to do this with JavaScript?
If i understand you correctly, you can do following:
// step 1 create list of names with classes
<ul>
<li class="person male">Alan</li>
<li class="person male">Ben</li>
<li class="person female">Cindy</li>
</ul>
// step 2 create dropdown list of genders
<select id="my-dropdown-id" name="gender">
<option value="male">Male</option>
<option value="female">Female</option>
</select>
// step 3 simple jQuery script
<script type="text/javascript">
$('#my-dropdown-id').change(function() {
$('.person').removeClass('selected');
$('.' + this.value).addClass('selected');
});
</script>
<style>
.selected{
background: yellow;
}
</style>
This is a very simple solution, though i believe it implements your idea at least theoretically.

Categories

Resources