Cra Crazy zy Tri Trick cks s wi with th Vi View ews - - PowerPoint PPT Presentation

cra crazy zy tri trick cks s wi with th vi view ews
SMART_READER_LITE
LIVE PREVIEW

Cra Crazy zy Tri Trick cks s wi with th Vi View ews - - PowerPoint PPT Presentation

Cra Crazy zy Tri Trick cks s wi with th Vi View ews PRESENTED TO Amani Mansour and Krystee Dryer Vi View ews s Mo More re tha than Ju Just st Li List sts When do views cross over to complex? How to approach a complex


slide-1
SLIDE 1

PRESENTED TO

Cra Crazy zy Tri Trick cks s wi with th Vi View ews

Amani Mansour and Krystee Dryer

slide-2
SLIDE 2

Vi View ews s – Mo More re tha than Ju Just st Li List sts

❶ When do views cross over to complex? ❷ How to approach a complex view. ❸ How to use hooks and javascript to get

the results you need.

DrupalCon 2018: Crazy Tricks with Views

slide-3
SLIDE 3

Amani Mansour

Software Engineer

Krystee Dryer

Technical Lead and Senior Software Engineer

Who we are

DrupalCon 2018: Crazy Tricks with Views

We’re Hiring!

slide-4
SLIDE 4

4

A full service digital experience agency

Nonprofit Marketing & Fundraising Changing the World UX & Visual Design Web & Mobile Development

+ + =

slide-5
SLIDE 5

One View with Three Needed Outcomes

slide-6
SLIDE 6

Background

  • League of Women

Voters has multiple leagues across the U.S.

  • Goal - to make it

easy for users to find their nearest local league by zip code

DrupalCon 2018: Crazy Tricks with Views

slide-7
SLIDE 7

Outcome #1: No Zip Code Entered

If no zip code is entered, show a summary list

DrupalCon 2018: Crazy Tricks with Views

slide-8
SLIDE 8

Outcome #2: User Enters Zip Code

If a zip code is entered, display the league with that matching zip code and show the state league

DrupalCon 2018: Crazy Tricks with Views

slide-9
SLIDE 9

Outcome #3: No Matching Zip Code Found

If a matching zip code is not found, display all leagues in the same state as the zip code and show the state league

DrupalCon 2018: Crazy Tricks with Views

slide-10
SLIDE 10

View Setup – Local Leagues

Created a view page display

Fields:

∙ League type ∙ Title

Filter Criteria:

∙ Published ∙ Content Type = Local League ∙ League Type = Local League ∙ Zip Code (exposed)

DrupalCon 2018: Crazy Tricks with Views

slide-11
SLIDE 11

View Setup – Local Leagues

Contextual Filter

∙ Content: Has taxonomy term ID

∙ Display summary when filter value is not in the URL ∙ Display record count with link

DrupalCon 2018: Crazy Tricks with Views

slide-12
SLIDE 12

Outcome #1: Achieved

DrupalCon 2018: Crazy Tricks with Views

slide-13
SLIDE 13

If you click

  • n a state…

DrupalCon 2018: Crazy Tricks with Views

slide-14
SLIDE 14

View Setup – State League

Created a view block display

Fields:

∙ League type ∙ Title

Filter Criteria:

∙ Published ∙ Content Type = Local League ∙ League Type = State League

DrupalCon 2018: Crazy Tricks with Views

slide-15
SLIDE 15

View Setup – State League

Contextual Filter

∙ Content: State

∙ When filter value not available, provide default value = Has taxonomy term id from url ∙ Load default filter from term page, load default filter from node page, limit terms by vocab = state, filter to items that share all terms

DrupalCon 2018: Crazy Tricks with Views

slide-16
SLIDE 16

View Setup – State League

Added the state league view block to the footer of the local league page view using a global view area

DrupalCon 2018: Crazy Tricks with Views

slide-17
SLIDE 17

Outcome #2 Almost Achieved

The state league is missing because the state tid is not in the url when a user searches by zip code

DrupalCon 2018: Crazy Tricks with Views

slide-18
SLIDE 18
  • Outcome #2 missing the state

league

  • Outcome #3 not achieved:

Display all leagues in the same state as the zip code entered if it did not match any results

Display state league

View Limitations

DrupalCon 2018: Crazy Tricks with Views

slide-19
SLIDE 19

Locate State League for Matching Zip Code

HOOK_views_pre_view – can be used to change things before the view is executed.

function lwv_views_pre_view(ViewExecutable $view, $display_id, array &$args) { if ($view->id() == 'local_leagues_by_state') { $exposedinput = $view->getExposedInput(); $zip = $exposedinput['field_zip_code_value']; if ($zip) { $args[0] = _get_state_by_zip($zip);

} } } If a zip code is entered, get the state where that zip code is located Get the input from the filter

DrupalCon 2018: Crazy Tricks with Views

slide-20
SLIDE 20

Outcome #2: Achieved

DrupalCon 2018: Crazy Tricks with Views

slide-21
SLIDE 21

Locate State for Not Matched Zip Code

HOOK_views_post_execute – can be used to alter results after the view is executed but before it is displayed.

function module_views_post_execute(ViewExecutable $view) { if ($view->id() == 'local_leagues_by_state') { if (!$view->total_rows) { $exposedinput = $view->getExposedInput(); $zip = $exposedinput['field_zip_code_value']; if ($zip) { $args = _get_state_by_zip($zip); // kint($args); die; if($args) { $response = new RedirectResponse('/local-leagues/find-local-league/' . $args . '?field_zip_code_value='); $response->send();

} } } } }

Test to see if view returns any results Send zip code to function and return state Once a state is returned, put it in the URL for the view to use as a contextual filter Grab the value of the zip code entered by the user

DrupalCon 2018: Crazy Tricks with Views

slide-22
SLIDE 22

Get State by Zip Code

  • _get_state_by_zip() is a function

we created that allows us to pass it a zip code value and it will return the state where that zip code exists

  • To achieve this, we used the

Google Maps Geocoding API

DrupalCon 2018: Crazy Tricks with Views

slide-23
SLIDE 23

Get State By Zip Code

function _get_state_by_zip($zip) { $uri = 'https://maps.googleapis.com/maps/api/geocode/json?address='. $zip .'&sensor=true&key=[key]'; try { $response = \Drupal::httpClient()->get($uri, array('headers' => array('Accept' => 'text/plain'))); $data = (string) $response->getBody(); if (empty($data)) { return FALSE; } } catch (RequestException $e) { return FALSE; } $dataArray = json_decode($data); $state = NULL; foreach($dataArray->results[0]->address_components as $data) { if ($data->types[0] == 'administrative_area_level_1') { $state = $data->long_name; } } if($state) { $term = \Drupal::entityTypeManager()

  • >getStorage('taxonomy_term')
  • >loadByProperties(['name' => $state]);

$ids = array_keys($term); return reset($ids); } return FALSE; } Call the google map geocoding api with zip

code and get response Response is in JSON format so we decode that into an object State information is held in the adminstrative_area_level_1 Use the state name obtained from the response and locate the taxonomy term that matches and get tid

slide-24
SLIDE 24

Outcome #3: Achieved

DrupalCon 2018: Crazy Tricks with Views

slide-25
SLIDE 25

View Switcher

slide-26
SLIDE 26

Background

Create a view switcher that allows users to switch the display between a card and list view

DrupalCon 2018: Crazy Tricks with Views

slide-27
SLIDE 27

View Setup

  • Created a block view

display

  • Format: Masonry

DrupalCon 2018: Crazy Tricks with Views

slide-28
SLIDE 28

View Setup

  • Global View

Header

○ Global text

area with html markup for the view switcher

DrupalCon 2018: Crazy Tricks with Views

slide-29
SLIDE 29

Masonry Methods

  • Methods are actions done by Masonry

instances

  • With jQuery, methods follow the jQuery UI

pattern .masonry( ‘methodName’ /* arguments */ )

  • https://masonry.desandro.com/methods.html

DrupalCon 2018: Crazy Tricks with Views

slide-30
SLIDE 30

.masonry(‘destroy’)

  • Destroy removes the

Masonry functionality and will return the element back to its pre-initialized state

DrupalCon 2018: Crazy Tricks with Views

slide-31
SLIDE 31

.masonry(‘destroy’) limitations

When masonry initializes it adds positioning on the masonry items (inline CSS). When it’s destroyed it removes what is added.

DrupalCon 2018: Crazy Tricks with Views

slide-32
SLIDE 32

Toggle Class

When the value of the select list changes If the select list value is equal to list view, then add the class ‘destroy- masonry’, else remove the class ‘destroy-masonry’

DrupalCon 2018: Crazy Tricks with Views

(function ($) { BF.init(function () { $('select[name="view-switcher"]').on( 'change', function() { var selectListValue = $(this).val(); var $masonryLayoutWrapper = $('.masonry-layout'); if(selectListValue == 'list-view'){ $masonryLayoutWrapper.addClass('destroy-masonry'); } else { $masonryLayoutWrapper.removeClass('destroy-masonry'); } }); }); })(jQuery);

slide-33
SLIDE 33

Success!

DrupalCon 2018: Crazy Tricks with Views

slide-34
SLIDE 34

Special Exposed Filters

slide-35
SLIDE 35

Background

  • View with exposed

filters with requirements Better Exposed Filters couldn’t solve

  • Needed Dropdowns

with checkboxes and selected filters in horizontal container

DrupalCon 2018: Crazy Tricks with Views

slide-36
SLIDE 36

Approach

  • Used Bootstrap

Multiselect as a base for the dropdowns

  • Custom jquery

for the selected filters

DrupalCon 2018: Crazy Tricks with Views

slide-37
SLIDE 37

Custom Module

  • Basic structure of the

custom module needed

  • Added the bootstrap-

multiselect.js file in the js directory

DrupalCon 2018: Crazy Tricks with Views

multiselect_facets

  • js
  • -bootstrap-multiselect.js
  • -multiselect_facets.js
  • css
  • -multiselect_facets.css
  • templates
  • -multiselects_facets.html.twig
  • multiselect_facets.info.yml
  • multiselect_facets.libraries.yml
  • multiselect_facets.module
slide-38
SLIDE 38

multiselect_facets: css: theme: css/multiselect_facets.css: {} js: js/multiselect_facets.js: {} dependencies:

  • core/jquery
  • core/drupal.ajax
  • core/drupal
  • core/drupalSettings
  • core/jquery.once

bootstrap_multiselect: js: js/bootstrap-multiselect.js: {} dependencies:

  • core/jquery
  • core/drupal.ajax
  • core/drupal
  • core/drupalSettings
  • core/jquery.once

Customizations (.libraries.yml file)

DrupalCon 2018: Crazy Tricks with Views

Define custom javascript library Define the bootstrap- multiselect javascript library

slide-39
SLIDE 39

/** * Implements hook_form_views_exposed_form_alter(). * */ function multiselect_facets_form_views_exposed_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) { $form['#attached']['library'][] = 'multiselect_facets/multiselect_facets'; $form['#attached']['library'][] = 'multiselect_facets/bootstrap_multiselect'; } /** * Implements hook_theme(). */ function multiselect_facets_theme() { return [ 'multiselect_facets' => [ 'variables' => [] ], ]; }

Customizations (.module file)

DrupalCon 2018: Crazy Tricks with Views

Using a hook_form_FORM_ID_alter() to find everywhere the exposed filters is used and attach libraries Some changes must be made to the exposed filter markup

slide-40
SLIDE 40

Customizations (.js file)

DrupalCon 2018: Crazy Tricks with Views

Allow the bootstrap multiselect to attach to form items that have an attribute of multiple=multiple

(function ($) { 'use strict'; Drupal.behaviors.facets = { 'attach': function (context, settings) { var $context = $(context); $('select[multiple="multiple"]').multiselect();

slide-41
SLIDE 41

Customizations (.js file)

DrupalCon 2018: Crazy Tricks with Views

slide-42
SLIDE 42

Views Plugins for Filtering

slide-43
SLIDE 43

Background

  • Plotting geolocated pins on a

google map

  • Wanted to be able to filter in

a dropdown by the name of the content (node) and return all nodes with same name

  • Traditional filters did not

satisfy this requirement (dropdown and keyword search working together)

DrupalCon 2018: Crazy Tricks with Views

slide-44
SLIDE 44

Views Filter Plugin

  • Drupal 8’s plugin system

allows custom fields, filters, sorts and other components for views to be created

  • Great for combining filter

functionality and leverage what Drupal already done for us

DrupalCon 2018: Crazy Tricks with Views

slide-45
SLIDE 45

Approach

  • Wanted the ease of a

dropdown box with the capabilities of a keyword search

  • It is easiest to model

your plugin after an existing one in core

  • Chose the InOperator

plugin to start

DrupalCon 2018: Crazy Tricks with Views

slide-46
SLIDE 46

Custom Module

  • Basic structure of the

custom module needed

  • Copied the

InOperator.php from the views module in core

DrupalCon 2018: Crazy Tricks with Views

modulename

  • src
  • -Plugin
  • --views
  • ---filter
  • ----ProgramTitles.php
  • modulename.info.yml
  • modulename.views.inc
slide-47
SLIDE 47

Customizations (init)

DrupalCon 2018: Crazy Tricks with Views

public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); $this->valueTitle = t('Allowed program titles'); $this->definition['options callback'] = array($this, 'generateOptions'); }

Basic init function that initializes the new views filter plugin

slide-48
SLIDE 48

Customizations (generateOptions)

DrupalCon 2018: Crazy Tricks with Views

public function generateOptions() { $query = \Drupal::database()->select('node_field_data', 'node_field_data'); $query->fields('node_field_data', array('nid', 'title')); $query->condition('node_field_data.status', '1'); $query->condition('node_field_data.type', 'program', 'IN'); $query->orderBy('node_field_data.title', 'ASC'); $data = $query->execute(); $results = $data->fetchAll(\PDO::FETCH_OBJ); $options = array(); foreach ($results as $result) { // $options[$result->nid] = substr($result->title, strpos($result->title, '- ') ); $program = explode(" | ", $result->title); $options[$program[1]] = $program[1]; $options = array_unique($options); natsort($options); } return $options;

}

Query the database to get the

  • ptions for the dropdown

Loop through the results and discard duplicates and set to alphabetical order by title Return the options for the filter

slide-49
SLIDE 49

Customizations (opSimple)

DrupalCon 2018: Crazy Tricks with Views

protected function opSimple() { if (empty($this->value)) { return; } $this->ensureMyTable(); $this->realField = 'title'; $programtitles = NULL; $where = db_or(); foreach ($this->value as $programtitle) { $where->condition( "$this->tableAlias.$this- >realField", '%' . db_like(trim($programtitle, " ,!?")) . '%', 'LIKE'); } $this->query->addWhere($this->options['group'], $where);

}

protected function opSimple() { if (empty($this->value)) { return; } $this->ensureMyTable(); // We use array_values() because the checkboxes keep keys and that can cause // array addition problems. $this->query->addWhere($this->options['group'], "$this->tableAlias.$this->realField", array_values($this->value), $this->operator); }

Customized function Original Function Add the where condition to the query to turn this into a keyword search

slide-50
SLIDE 50

Amani Mansour

Amani.mansour@beaconfire-red.com

Krystee Dryer

Krystee.dryer@beaconfire-red.com

Questions?

DrupalCon 2018: Crazy Tricks with Views