Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add race filter #140

Merged
merged 6 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
105 changes: 62 additions & 43 deletions client/templates/sections/current-prosecutors/current-prosecutors.html
Original file line number Diff line number Diff line change
@@ -1,53 +1,72 @@
<template name="currentProsecutors">

<div class="row my-5">
<div class="container mx-auto text-center">
<h3>Filter by Role</h3>
<div class="mx-auto text-left" style="width: fit-content;">
{{#each filter in roleFilters}}
<div class="checkbox">
<label>
<input class="role-filter" name={{filter}} type="checkbox">
{{filter}}
</label>
<div class="row my-5">
<div class="col-sm">
<div class="container mx-auto text-center">
<h3>Role</h3>
<div class="mx-auto text-left" style="width: fit-content;">
{{#each filter in roleFilters}}
<div class="checkbox">
<label>
<input class="role-filter" name={{filter}} type="checkbox">
{{filter}}
</label>
</div>
{{/each}}
</div>
</div>
</div>
<div class="col-sm">
<div class="container mx-auto text-center">
<h3>Race/Ethnicity</h3>
<div class="mx-auto text-left" style="width: fit-content;">
{{#each filter in raceFilters}}
<div class="checkbox">
<label>
<input class="race-filter" name={{filter}} type="checkbox">
{{filter}}
</label>
</div>
{{/each}}
</div>
</div>
</div>
{{/each}}
</div>
</div>
</div>

<div class="container-fluid mx-auto text-center">
{{#if attorneys}}
<div id="prosecutor-list">
<ul>
{{#each attorney in attorneys}}
<li class="col-sm-6 col-md-4 col-lg-3 single-attorney">
<a class="card" href="{{pathFor 'attorneyView' data=attorney}}">
<h3 class="card-header">{{attorney.name}}</h3>
{{#if attorney.headshot}}
<div class="thumbnail" style="background-image:url('{{attorney.headshot}}')"></div>
{{else}}
<div class="thumbnail" style="background-image:url('images/anon-prosecutor.jpg')"></div>
{{/if}}
<div class="card-body">
<h4 class="card-title">{{attorney.role}}</h4>
<h5 class="card-subtitle">{{attorney.state}}</h5>
<div class="card-text">
{{#if attorney.county}}<p class="card-text">{{attorney.county}}</p>{{/if}}
{{#if attorney.district}}<p class="card-text">{{attorney.district}}</p>{{/if}}
</div>
<div class="container-fluid mx-auto text-center">
{{#if attorneys}}
<div id="prosecutor-list">
<ul>
{{#each attorney in attorneys}}
<li class="col-sm-6 col-md-4 col-lg-3 single-attorney">
<a class="card" href="{{pathFor 'attorneyView' data=attorney}}">
<h3 class="card-header">{{attorney.name}}</h3>
{{#if attorney.headshot}}
<div class="thumbnail" style="background-image:url('{{attorney.headshot}}')"></div>
{{else}}
<div class="thumbnail"
style="background-image:url('images/anon-prosecutor.jpg')"></div>
{{/if}}
<div class="card-body">
<h4 class="card-title">{{attorney.role}}</h4>
<h5 class="card-subtitle">{{attorney.state}}</h5>
<div class="card-text">
{{#if attorney.county}}<p class="card-text">{{attorney.county}}</p>{{/if}}
{{#if attorney.district}}<p class="card-text">{{attorney.district}}</p>{{/if}}
</div>
</div>
<div class="card-footer text-muted">{{#if attorney.appointed}}
Appointed: <p class="card-text">
{{formatDate attorney.appointed}}</p>{{/if}}</div>
</a>
</li>
{{/each}}
</ul>
</div>
<div class="card-footer text-muted">{{#if attorney.appointed}}Appointed: <p class="card-text">
{{formatDate attorney.appointed}}</p>{{/if}}</div>
</a>
</li>
{{/each}}
</ul>
{{else}}
<p>No data available.</p>
{{/if}}
</div>
{{else}}
<p>No data available.</p>
{{/if}}
</div>


</template>
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
import {Template} from 'meteor/templating';
import {ReactiveDict} from 'meteor/reactive-dict';

import { Attorneys } from '../../../../imports/api/attorneys.js';
import {Attorneys} from '../../../../imports/api/attorneys.js';
import './current-prosecutors.html';

Template.currentProsecutors.onCreated(function () {
this.state = new ReactiveDict();
this.state.setDefault({
selectedRoleFilters: []
selectedRoleFilters: [],
selectedRaceFilters: []
});
});

Expand All @@ -20,11 +21,28 @@ Template.currentProsecutors.helpers({
'Municipal Attorney'
]
},
raceFilters() {
return [
'American Indian',
'Asian',
'Black',
'Hispanic',
'Pacific Islander',
'White'
]
},
attorneys() {
const selectedRoleFilters = Template.instance().state.get("selectedRoleFilters")
return selectedRoleFilters.length > 0
? Attorneys.find({ "role": { $in: selectedRoleFilters } }).fetch()
: Attorneys.find().fetch()
const selectedRaceFilters = Template.instance().state.get("selectedRaceFilters")
if (selectedRoleFilters.length > 0 && selectedRaceFilters.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, I think there is a more elegant way to do this, which also would scale a lot better as we add filters. Something like:

  let filter = null;

  if (selectedRoleFilters.length > 0) {
    filter = { ...filter, role: { $in: selectedRoleFilters } };
  }
  if (selectedRaceFilters.length > 0) {
    filter = { ...filter, race: { $in: selectedRaceFilters } };
  }

  return filter ? Attorneys.find(filter).fetch() : Attorneys.find().fetch()
  }

I haven't actually tried that code, but I'm pretty sure that should work. If Meteor supports passing in empty objects or null as filter then the return can be simplified even further by simply returning Attorneys.find(filter).fetch(), but I have no clue about that as I'm quite noob as Meteor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you reached out. I wanted to have this exact conversation with you. I have never worked with Meteor before/also was tired and couldnt find a better paradigm online at the time. This looks like a good solution. Do you think I should go add this in or should @CodeSmitty as a part of his work? He might end up having to pull down from upstream which as a newer dev may be a pain for him.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like you guys go this down. Don't wait on me, if you can fix it. Like I said, I'm fairly new to this only a year and a half into javascript. 2nd Day trying to understand Meteor. I joined to the hactoberfest and I'm not sure if I'm over my head.

Copy link
Contributor

@Zoe7 Zoe7 Oct 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be clear, the code snippet that I posted above is mostly javascript functionality, the only "meteor" specific thing in there is the Attorneys.find(filter).fetch() part.
What I'm using to build up the filter object is a javascript feature called spread operator. It allows us to build a new object based on the content of another object, which is what I'm doing with this line: filter = { ...filter, race: { $in: selectedRaceFilters } }. I'm basically saying: take whatever was in the old filter object, add race: { $in: selectedRaceFilters } to it and make a new object out of that.
If you don't know that syntax, I would highly recommand looking at some tutorials for it and playing around with it a little, it's super useful!

Do you think I should go add this?

You're very welcome to do so! I just started a new job yesterday so I'm a bit busy and mentally overloaded right now 😅

He might end up having to pull down from upstream

At this point, he's going to have to do that anyway, since his changes would conflict with ours and they need to be resolved 😕 Github has a lot of good guides on how to handle forks and one in particular explaining how to keep a forked repository in sync. And I'm happy to answer questions and help with it if needed 😄

I joined to the hactoberfest and I'm not sure if I'm over my head.

Meteor definitely got me challenged, and I haved worked in the industry for 6 years now 😄 It works, but it's definitely a little more oldschool and harder to get started with than newer frameworks. But I think it's super cool that you're joining hacktoberfest, it's a great way to learn new stuff and get a little challenged! Let me know if you have any questions in particular that I can answer, I'd be happy to help!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I understand spread operators, I'm not the best at it. But working with react, did help me use them in other cases. What I ment is, how to give Meteor my changes so I can see them live. I'm reading through it all though, I just pulled what you two added to it. Looking at it from there. One line that did confuse me a little was the race:{$in: selectedRaceFilter.

Which for me it means give the new object data and store in the race object of.. the $in it's kinda what I didn't know if that's a variable name chosen. I'm used to seeing the $ symbol in more of a back tick. string add ${data} string.
Apologies for my typos, also I appreciate you all taking the time to explain things to me, and not letting me quit lol.
I'm at least playing with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$in is a mongoDB operator. It selects records that match any of the values provided in the selectedRaceFilter. So if we have "Black" and "Hispanic" in the selectedRaceFilter, the query would pull all attorneys that have those set in the "race" field.

https://docs.mongodb.com/manual/reference/operator/query/in/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that makes much more sense. I'll play around with it after work and see what I get. Thank you!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inviting @rohitkswat to the party, as he untangled this logic with #157

return Attorneys.find({"role": {$in: selectedRoleFilters}, "race": {$in: selectedRaceFilters}}).fetch()
} else if (selectedRoleFilters.length > 0 && selectedRaceFilters.length === 0) {
return Attorneys.find({"role": {$in: selectedRoleFilters}}).fetch()
} else if (selectedRoleFilters.length === 0 && selectedRaceFilters.length > 0) {
return Attorneys.find({"race": {$in: selectedRaceFilters}}).fetch()
} else {
return Attorneys.find().fetch()
}
},
});

Expand All @@ -36,5 +54,13 @@ Template.currentProsecutors.events({
? selectedRoleFilters.filter((value) => value !== filter)
: [...selectedRoleFilters, filter]
instance.state.set("selectedRoleFilters", newSelectedRoleFilters)
},
"change .race-filter"(event, instance) {
const filter = event.currentTarget.name
const selectedRaceFilters = instance.state.get("selectedRaceFilters")
const newSelectedRaceFilters = selectedRaceFilters.includes(filter)
? selectedRaceFilters.filter((value) => value !== filter)
: [...selectedRaceFilters, filter]
instance.state.set("selectedRaceFilters", newSelectedRaceFilters)
}
})
59 changes: 32 additions & 27 deletions imports/api/attorneys.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
import { Mongo } from 'meteor/mongo';
import {Mongo} from 'meteor/mongo';

import SimpleSchema from 'simpl-schema';

export const Attorneys = new Mongo.Collection( 'Attorneys' );
export const Attorneys = new Mongo.Collection('Attorneys');

if ( Meteor.isServer ) {
Attorneys._ensureIndex( {
name: 1,
role: 1,
state: 1
});
if (Meteor.isServer) {
Attorneys._ensureIndex({
name: 1,
role: 1,
state: 1
});
}

Attorneys.allow({
insert: () => false,
update: () => false,
remove: () => false
insert: () => false,
update: () => false,
remove: () => false
});

Attorneys.deny({
insert: () => true,
update: () => true,
remove: () => true
insert: () => true,
update: () => true,
remove: () => true
});

let AttorneysSchema = new SimpleSchema({
'name': {
type: String,
label: 'The name of this attorney.'
},
'role': {
type: String,
label: 'The role of this attorney.'
},
'state': {
type: String,
label: 'The state of this attorney.'
}
'name': {
type: String,
label: 'The name of this attorney.'
},
'role': {
type: String,
label: 'The role of this attorney.'
},
'state': {
type: String,
label: 'The state of this attorney.'
},
'race': {
type: String,
label: 'The race of this attorney.'
},

});

Attorneys.attachSchema( AttorneysSchema );
Attorneys.attachSchema(AttorneysSchema);