Filtering popup menu - javascript

In general, I need to make a pop-up menu with a choice of a category, everything works for me, but there is one point that needs to be improved.
When the category has already been selected, it is necessary that in the blog-filter class, All should be changed to the selected category, I tried many options, but all the non-working ones turned out to be.
html
<div class="blog-filter">
<div class="blog-filter_item active js-filter-blog-list" data-filter="all">All</div>
</div>
<div class="blog-filter-container">
<div class="container">
<h1 class="blog-filter-title">Choose Category</h1>
<div class="item-wrapper">
<div class="blog-filter_item active" data-filter="all">All</div>
#foreach($categories as $category)
<div class="blog-filter_item" data-filter=".category_{{$category->id}}">{{ $category->title }} ({{ $category->articles_count }})</div>
#endforeach
</div>
</div>
</div>
#foreach ($articles as $article)
<div class="blog-list category_{{ $article->blog_category_id }}">
<div class="article article--left" >
<h2 class="article_title">{{ $article->title }}</h2>
</div>
<div class="article article--right">
<h2 class="article_title">{{ $article->title }}</h2>
</div>
</div>
#endforeach
js
$('.js-filter-blog-list').on('click', event => {
const modalFilter = document.querySelector('.blog-filter-container');
$(modalFilter).toggleClass('open');
});
document.querySelectorAll('.blog-filter_item').forEach(el => {
el.addEventListener('click', () => {
document
.querySelector('.blog-filter_item.active')
.classList.remove('active');
el.classList.add('active');
var dataFilter = $(el).attr('data-filter');
if (dataFilter == 'all') {
$('.blog-list').show();
}
else {
$('.blog-list').hide();
$(dataFilter).show();
}
});
});

Solution:
#foreach($categories as $category)
<div class="blog-filter_item" data-filter=".category_{{$category->id}}" value="{{ $category->title }} ({{ $category->articles_count }})>{{ $category->title }} ({{ $category->articles_count }})</div>
#endforeach
var dataFilter = $(el).attr('data-filter');
var value = $(el).attr('value');
if (dataFilter == 'all') {
$('.blog-list').show();
$('.js-filter-blog-list').text('All');
}
else {
$('.blog-list').hide();
$(dataFilter).show();
$('.js-filter-blog-list').text(value);
}

Related

Vue : Accessing Nested Object Component's Values

I have problems accessing this "name" property on the component. I can only access it statically.
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
{{ channel.users[0].name }}
</p>
</div>
</template>
Here is an Image of my Vue Devtools
So I have an v-for loop over channels, and I want to: Access the Usernames for each channel (if it is not my own preferably as "username" is set on my own i think its easy to exclude it right?) So that in the end In Channel 1 when there are 2 Users , I want to show the corresponding username, so the "other username", the one i am chatting with, and he should see my name that is the initial goal.
I thought of doing something like this:
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<!-- {{ channel.users[0].name }} -->
<span v-for="user,key in channel">{{key}}</span>
</p>
</div>
it at least displays the content of the channels object for each channel, but something like this isnt gonna work: key.user.name , unfortunately im stuck here. please help :)
edit: here is a dd() of the view
click
EDIT 2: Parent Data Provided:
//chat-app.blade.php
<div id="app">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Chats</div>
<vue-chat :channels="{{ $channels }}" ></vue-chat>
</div>
</div>
</div>
</div>
</div>
</div>
//<vue-chat> component
<template>
<div class="chat">
<div class="container">
<div class="row">
<div class="col-md-3">
<vue-chat-channels
:channels="channels"
:active-channel="activeChannel"
#channelChanged="onChannelChanged"
:username="sername"
></vue-chat-channels>
</div>
<div class="col-md-3">
<vue-chat-messages :messages="messages"></vue-chat-messages>
</div>
<div class="col-md-3">participants</div>
</div>
<div class="message-input-wrapper col-md-12"><vue-chat-new-message :active-channel="activeChannel"
:username="username"></vue-chat-new-message></div>
</div>
</div>
</template>
<script>
export default {
props: ["channels"],
data() {
return {
activeChannel: this.channels[0].id,
messages: [],
username: ''
};
},
methods: {
fetchMessages() {
let endpoint = `/channels/${this.activeChannel}/messages`;
axios.get(endpoint).then(({ data }) => {
this.messages = data;
});
},
onChannelChanged(id) {
this.activeChannel = id;
this.fetchMessages();
}
},
created() {
this.fetchMessages();
axios.get('/userfetch').then( ({data}) => {
console.log("Current User: "+data.name);
this.username = data.name;
});
console.log(this.channels[0].name);
// for (let channel of this.channels) {
this.channels.forEach(channel => {
// Channelname
window.Echo.channel('presence-'+channel.name)
.listen('MessageSent', (channel) => {
console.log(channel.data.message);
this.messages.push({ message: channel.data.message, author_username: channel.data.author_username});
if (this.activeChannel == channel.id) {
console.log("received message");
}
});
});
}
};
</script>
<style>
</style>
//ChatController.php
public function index()
{
$channels = Channel::with('users')->whereHas('users', function($q) {
$q->where('user_id',Auth::id());
})->get();
$user = Auth::user()->name;
return view('chat-app' , compact('channels','user'));
}
Short Explanation: ChatController returns the blade view, which has the data channels and user (my username) , and then vue comes into play which should pass down the prop of my username but i couldnt get it to work just yet
So you need to access users in every channel.
You can try like this:
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<span v-for="user in channel.users">
{{ user.name }}
</span>
</p>
</div>
This should work. If you have errors provide it here.
If you need to compare every user you can do it simply with v-if:
<span v-for="user in channel.users">
<span v-if="user.name === parentdata">
{{ user.name }}
</span>
</span>

How to read data from a v-for (vue.js)?

Given the next v-for:
<div class="container-fluid" id="networdapp" style="display:none;">
<div class="row" >
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light" >
<div class="card-header text-center" > {{ result.title }} </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
<a href="/details" class="btn btn-info" #click="getData(result)" >Details</a>
</div>
</div>
</div>
</div>
</div>
And the next Vue.js script:
<script type="text/javascript">
const vm = new Vue({
el: '#networdapp',
data: {
results:[]
},
methods: {
getData: function(result){
window.alert($(this).parents("#networdapp").find(".card-header.text-center").outerHTML);
window.alert(document.getElementsByClassName("card-header").outerHTML);
window.alert(result.outerHTML);
}
},
mounted() {
axios.get('/getJson')
.then(response => {
this.results = response.data;
})
.catch( e => {
console.log(e);
});
}
});
</script>
I want to get data from a specific iteration,let's say if I click the "Details" button of the 3rd div from the v-for I want to get the {{result.title }} data from the 3rd for.Is it possible?I've been reading the Vue.js documentation but I didn't find anything about reading the data from DOM.If it is not possible,than how can I do that without Vue.js?Is there any other option?
The main goal is to get this data and to put it into a js object passing it to another webpage.
you have to pass index key and use is to get from results's position.
change the for loop div into
<div v-for="(result,i) in results" :key="i" class="col-sm-6" >
also chnange the methods parameter
<a href="/details" class="btn btn-info" #click="getData(i)" >Details</a>
and the method will get the index key and here i have used console to see the result.title that you have wanted. you can use it any how you want.
getData: function(key){
console.log(this.results[key].title)
}
so
Given the next v-for:
<div class="container-fluid" id="networdapp" style="display:none;">
<div class="row" >
<div v-for="(result,i) in results" :key="i" class="col-sm-6" >
<div class="card m-3 h-240 bg-light" >
<div class="card-header text-center" > {{ result.title }} </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
<a href="/details" class="btn btn-info" #click="getData(i)" >Details</a>
</div>
</div>
</div>
</div>
And the next Vue.js script:
<script type="text/javascript">
const vm = new Vue({
el: '#networdapp',
data: {
results:[]
},
methods: {
getData: function(key){
console.log(this.results[key].title)
}
},
mounted() {
axios.get('/getJson')
.then(response => {
this.results = response.data;
})
.catch( e => {
console.log(e);
});
}
});
To get the data you want to access in the results array, you can use an index in your v-for loop
v-for="(result, index) in results"
you can check the docs here https://v2.vuejs.org/v2/guide/list.html
I also strongly recommend you to add a key attribute after the v-for to help vue.js
keep track of each result, see https://v2.vuejs.org/v2/guide/list.html#key

Group same strings in array and count them

This is an Angular project and I have data that comes from the server. I am creating three lists. I have three types of sentiment and each sentiment has a description
for (const sentiment of this.dataSource.allFavourabilities) {
if (sentiment.sentiment === 'Positive') {
this.positiveList.push(sentiment);
}
if (sentiment.sentiment === 'Negative') {
this.negativeList.push(sentiment);
}
if (sentiment.sentiment === 'Neutral') {
this.neutralList.push(sentiment);
}
}
This is how it looks like when I console.log that.
coverageId:137
description:"Positive"
id:119
sentiment:"Positive"
In HTML I am listing this in three divs and the only constant is sentiment which is displayed as an icon, the description can be different. But client mainly types positive, negative or neutral so I get an ugly list with same data. I want to filter that so it is a matching string in the description and I have positive in the description like 50 times, in my HTML it should say
Preferred outcome:
positive(50)
negative(2)
neutral
and not
positive
positive
positive
positive etc.
negative
negative
neutral
This is my HTML:
<div class="form-item favourability-wrapper flex">
<div class="column" *ngIf="positiveList">
<div class="sentiment-label">Positive</div>
<ng-container *ngFor="let a of positiveList">
<div class="sentiment sentiment-positive ">
<i class="fas fa-smile"></i>
<div class="description">{{ a.description }}</div>
</div>
</ng-container>
</div>
<div class="column" *ngIf="negativeList">
<div class="sentiment-label">Negative</div>
<ng-container *ngFor="let b of negativeList">
<div class="sentiment sentiment-neutral">
<i class="fas fa-meh"></i>
<div class="description">{{ b.description }}</div>
</div>
</ng-container>
</div>
<div class="column" *ngIf="neutralList">
<div class="sentiment-label">Neutral</div>
<ng-container *ngFor="let c of neutralList">
<div class="sentiment sentiment-negative">
<i class="fas fa-frown"></i>
<div class="description">{{ c.description }}</div>
</div>
</ng-container>
</div>
</div>
Change this to a html element that shows the length
<ng-container *ngFor="let a of positiveList">
<div class="sentiment sentiment-positive ">
<i class="fas fa-smile"></i>
<div class="description">{{ a.description }}</div>
</div>
</ng-container>
to
<div *ngIf="positiveList">
{{ '(' + (positiveList?.length || '0')+')' }}
</div>
You can try this:
<div class="form-item favourability-wrapper flex">
<div class="column" *ngIf="positiveList">
<div class="sentiment-label">Positive</div>
<div class="sentiment sentiment-positive ">
<i class="fas fa-smile"></i>
<div class="description">({{ positiveList.length > 0 ? positiveList.length : '0' }})</div>
</div>
</div>
<div class="column" *ngIf="neutralList">
<div class="sentiment-label">Neutral</div>
<div class="sentiment sentiment-neutral">
<i class="fas fa-meh"></i>
<div class="description">({{ neutralList.length > 0 ? neutralList.length : '0' }})</div>
</div>
</div>
<div class="column" *ngIf="negativeList">
<div class="sentiment-label">Negative</div>
<div class="sentiment sentiment-negative">
<i class="fas fa-frown"></i>
<div class="description">({{ negativeList.length > 0 ? negativeList.length : '0' }})</div>
</div>
</div>
</div>
<div class="form-item favourability-wrapper flex">
<div class="column" *ngIf="positiveList">
<div class="sentiment-label">Positive{{ positiveList.length ? '(' + positiveList.length + ')' : '' }}</div>
</div>
<div class="column" *ngIf="negativeList">
<div class="sentiment-label">Negative{{ negativeList.length ? '(' + negativeList.length + ')' : '' }}</div>
</div>
<div class="column" *ngIf="neutralList">
<div class="sentiment-label">Neutral{{ neutralList.length ? '(' + neutralList.length + ')' : '' }}</div>
</div>
</div>
maybe this works for you, you can use Array.length to get the count.
Since you're asking for help, let me help you improve your code :
this.feelings = [
{ name: 'Positive', sentiments : [] },
{ name: 'Negative', sentiments : [] },
{ name: 'Neutral', sentiments : [] },
];
for (const sentiment of this.dataSource.allFavourabilities) {
if (sentiment.sentiment === 'Positive') {
this.feelings[0].sentiments.push(sentiment);
}
if (sentiment.sentiment === 'Negative') {
this.feelings[1].sentiments.push(sentiment);
}
if (sentiment.sentiment === 'Neutral') {
this.feelings[2].sentiments.push(sentiment);
}
}
<!-- I'll let you append the classes to your convenience -->
<div *ngFor="let feeling of feelings">
{{ feeling.name }} : {{ feeling.sentiments.length }}
</div>
See how the HTML got reduced ? We can even reduce the typescript further with this
this.feelings: { name: string, sentiments : any[] }[] = this.dataSource.allFavourabilities
.reduce((p, n) => {
if (!p.find(feeling => feeling.name === n.sentiment)) {
p.push({ name: n.sentiment, sentiments : []});
}
p.find(feeling => feeling.name === n.sentiment).sentiments.push(n);
return p;
}, []);

Page not being rendered after performing search

Below is the standard page in HTML with pagination working well. The problem arises when I perform a search. I would like to know why when I run the search it complains that "vehicles is an undefined variable"
#foreach($all as $one)
<div class="card-description">
<div class="card-text">
<div class="card-text-wrapper">
<div class="card-details">
<p class="vehicle-name">{{$one->make}}</p>
<p class="vehicle-details">{{$one->year}}</p>
<p class="vehicle-details">{{$one->type}}</p>
</div>
</div>
</div>
<div class="card-text">
<div class="card-text-wrapper">
<h1 class="price-tag">ยข {{$one->price}}</h1>
</div>
</div>
</div>
{{$all->links()}}
#endforeach
Below is the javascript function I tried for performing the search but unfortunately I do not know how to update the pagination to accept the new search values:
function searchVehicle(){
var make = document.getElementById("vehicle_make");
var strMake = make.options[make.selectedIndex].text;
var model = document.getElementById("vehicle_model");
var strModel = model.options[model.selectedIndex].text;
var cardDisplay = document.getElementById("card_display");
var cardDeck = document.getElementById("card_deck");
var strUrl = vehicle_url + strMake + '/' +strModel;
var obj = sendRequest(strUrl);
while (cardDeck.firstChild) {
cardDeck.removeChild(cardDeck.firstChild);
}
}
Below is my form which would be performing the search
{{ Form::open(['route' => 'search','method' => 'GET']) }}
<div>
<div class="wrapper-dropdown-5" tabindex="1" >
<span class="placeholder">Select make</span>
<ul class="dropdown" style="z-index:1000" name="mak" id="vehicle_make">
#foreach($vehicles as $vehicle)
{{--{{$vehicle->id}}--}}
<li class="option-make" id="make" value="{{$vehicle->make}}"><a>{{$vehicle->make}}</a></li>
#endforeach
</ul>
</div>
<div id="dd" class="wrapper-dropdown-5 inactive" tabindex="2" >
<span class="placeholder">Select model</span>
<ul class="dropdown" id="vehicle_model">
</ul>
</div>
</div>
</div>
<div class="button-wrap">
{{Form::submit('Search', ['class' => 'submit-button'])}}
</div>
{{ Form::close() }}
Below is the way I tried to display the search results but had an error that "vehicles" is an undefined variable:
public function searchVehicle(SearchVehicleRequest $request){
$make=$request->input('make');
$model=$request->input('model');
$results = Vehicles::where('make', 'LIKE', '%'.$make. '%')->orWhere('model','LIKE', '%'.$vehicle_model.'%')->paginate(2);
return Response::json(\View::make('Garages.home', array('all' => $results))->render());
}
And my route:
Route::get('search', ['as' => 'search', 'uses' => 'VehiclesController#searchVehicle']);
I can populate the HTML but don't know how to update the pagination..unless this whole process is wrong and there is a simpler way to get this done with ajax? or is page rendering the wrong way to go for something like this??

AngularJS unique tab data for each tab

I am pretty close to having this app finished, but have one last hurdle. I am dynamically populating tabs and data via the WordPress Rest API and when I only had 2 tabs it worked wonderfully, but when I added tab 3 and 4 I ran into issues. When I click tabs 2-4 all tabs receive the "active" class instead of just the one that was clicked; thus also all 3 tabs content data also displays.
Here is the code:
var homeApp = angular.module('homeCharacters', ['ngSanitize']);
homeApp.controller('characters', function($scope, $http) {
$scope.myData = {
tab: 0
}; //set default tab
$http.get("http://bigbluecomics.dev/wp-json/posts?type=character").then(function(response) {
$scope.myData.data = response.data;
});
});
homeApp.filter('stripTags', function() {
return function(text) {
return text ? String(text).replace(/<[^>]+>/gm, '') : '';
};
});
<section class="characters" ng-app="homeCharacters" ng-controller="characters as myData">
<div class="char_copy">
<h3>Meet the Characters</h3>
<div class="char_inject" ng-repeat="item in myData.data" ng-show="myData.tab === item.menu_order">
<div class="copy_wrap">
<h3>{{ item.acf.team }}:</h3>
<h2>{{ item.acf.characters_name }} <span>[{{item.acf.real_name}}]</span></h2>
<p class="hero_type">{{ item.acf.hero_type }}</p>
<div class="description" ng-repeat="field in item.acf.character_description">
<p>{{field.description_paragraph}}</p>
</div>
Learn More
</div>
<div class="image_wrap">
<img src="{{ item.acf.homepage_full_image.url }}" />
</div>
</div>
</div>
<div class="char_tabs">
<nav>
<ul ng-init="ch.tab = 0">
<li class="tab" ng-repeat="item in myData.data" ng-class="{'active' : item.menu_order == myData.tab}">
<a href ng-click="myData.tab = item.menu_order">
<img src="{{ item.featured_image.source }}" />
<div class="tab_title_wrap">
<h3>{{ item.acf.characters_name }}</h3>
</div>
</a>
</li>
</ul>
</nav>
</div>
</section>
I would love any ideas! Thanks!
The code seems to work, see Fiddle. What are the values of menu_order? If they are the same for cases 2-4, then that would explain the behaviour.

Categories

Resources