Feed aggregator

Shomeya: Model Your Data with Drupal and Domain-driven Design

Drupal News - January 20, 2015 - 9:00am

On of the things I've blogged about recently when talking about my upcoming book Model Your Data with Drupal is domain-driven design. While domain-driven design is important and something that I hope to touch on in the future, I've decided it's too much to cover in one book, and I'm refocusing Model Your Data with Drupal on basic object oriented principles.

If you want to know more about this decision and what will be covered in Model Your Data with Drupal, read on.

Read more

Drupal Watchdog: Something Borrowed, Something Drupal

Drupal News - January 20, 2015 - 8:59am
Feature


Drupal 8 represents a radical shift, both technically and culturally, from previous versions. Perusing through the Drupal 8 code base, many parts may be unfamiliar. One bit in particular, though, is especially unusual: A new directory named /core/vendor. What is this mysterious place, and who is vending?

The "vendor" directory represents Drupal's largest cultural shift. It is where Drupal's 3rd party dependencies are stored. The structure of that directory is a product of Composer, the PHP-standard mechanism for declaring dependencies on other packages and downloading them as needed. We won't go into detail about how Composer works; for that, see my article in the September 2013 issue of Drupal Watchdog, Composer: Sharing Wider.

But what 3rd party code are we actually using, and why?

Crack open your IDE if you want, or just follow along at home, as we embark on a tour of Drupal 8's 3rd party dependencies. (We won't be going in alphabetical order.)

Guzzle

Perhaps the easiest to discuss is Guzzle. Guzzle is an HTTP client for PHP; that is, it allows you to make outbound HTTP requests with far more flexibility (and a far, far nicer API) than using curl or some other very low-level library.

Drupal had its own HTTP client for a long time... sort of. The drupal_http_request() function has been around longer than I have, and served as Drupal's sole outbound HTTP utility. Unfortunately, it was never very good. In fact, it sucked. HTTP is not a simple spec, especially HTTP 1.1, and supporting it properly is difficult. drupal_http_request() was always an after-thought, and lacked many features that some users needed.

Blink Reaction: Give me a Swiss knife, Pleeease!

Drupal News - January 20, 2015 - 8:25am
All the annoying CSS stuff we don't want to do in 1 tool. One tool for stylesheets

EchoDitto Tech Blog: Code Management in Drupal 7 using Features, Ctools, and Panels

Drupal News - January 20, 2015 - 8:22am

Code structure is something most Drupal developers wrestle with. There are tons of modules out there that make our lives easier (Views, Display Suite, etc.) but managing database configuration while maintaining a good workflow is no easy challenge. Today I'm going to talk about a few approaches I use in my work here at Echo. We will be using a simple use case of creating a paginated list of blog posts. To start, we're going to talk about the workflow from a high level, then we'll get into the modules that leverage Drupal in a way that makes sense. Finally, we'll have some code samples to help guide things along.

Workflow

This will vary a bit based on what you need, but the idea behind this is we never want to redo our work. Ideally we'd like to design a View or functionality once on our local, and then package it and push it up. Features is a big driving force behind this. Beyond that, we want things like page structures and custom code to have a place to live that makes sense. So, for this example we will be considering the idea of a paginated list of Blog Posts. This is a heavy hammer to be swinging at such a solved task, but we will get into why this is good later on.

  • Create a new Feature that requires ctools and panels (and not views!)
  • Open up the generated .module file and declare the ctool plugin directory
  • Create the plugins/content_types/blog_posts.inc file
  • Define the needed functions within blog_posts.inc to make it work
  • Add the newly created content type to a page in Page Manager
  • Add everything we care about to the Feature and export it for deployment
Installation

This only assumes that you have a working Drupal installation and some knowledge of how to install modules. In this case, we will be using drush to accomplish this, but feel free to pick your poison here. Simply run the following commands and answer yes when prompted.

drush dl ctools ds features panels strongarm drush en ctools ds features panels strongarm page_manager

What we have done here is install and enable a strong foundation on which we can start to scaffold our site. Note that I won't be getting into folder structure too much, but there are some more steps before this you would have to take to ensure contrib, custom, and features all make it to their own place. We wave our hands at this for now.

Features

The first thing we're going to do is generate ourselves a Feature. Simply navigate to Structures -> Features -> Create Feature and you will see a screen that looks very similar to this. Fill out a name, and have it require ctools and panels for now.

This will generate a mostly empty feature for us. The important part we want here is the ability to turn it on and off in the Features UI, and the structure (that we didn't have to create manually!) which includes a .module and .info file is ready to go for us. That being said, we're going to open it up and tell it where to find the plugins. The code to do that is below, and here is a screenshot of the directory structure and code to make sure you're on the right track. Go ahead and create the plugins directory and associated file as well.

function blog_posts_ctools_plugin_directory($owner, $plugin_type) { return 'plugins/' . $plugin_type; } Chaos Tools

Known more commonly as ctools, this is a module that allows us this plugin structure. For our purposes, we've already made the directory and file structure needed. Now all we have to do is create ourselves a plugin. There are three key parts to this: plugin definition, render function, and form function. These are all defined in the .inc file mentioned above. There are plenty of resources online that get into the details, but basically we're going to define everything that gets rendered in code and leverage things like Display Suite and the theme function for pagination. This is what we wind up with:

<?php   /** * Plugin definition */ $plugin = array( 'single' => TRUE, 'title' => t('Blog Post Listing'), 'description' => t('Custom blog listing.'), 'category' => t('Custom Views'), 'edit form' => 'blog_post_listing_edit_form', 'render callback' => 'blog_post_listing_render', 'all contexts' => TRUE, );   /** * Render function for blog listing * @author Austin DeVinney */ function blog_post_listing_render($subtype, $conf, $args, &$context) { //Define the content, which is built throughout the function $content = '';   //Query for blog posts $query = new EntityFieldQuery(); $query->entityCondition('entity_type', 'node', '=') ->entityCondition('bundle', 'blog_post', '=') ->propertyCondition('status', NODE_PUBLISHED, '=') ->pager(5);   //Fetch results, and load all nodes $result = $query->execute();   //If we have results, build the view if(!empty($result)) { //Build the list of nodes $nodes = node_load_multiple(array_keys($result['node'])); foreach($nodes as $node) { $view = node_view($node, 'teaser'); $content .= drupal_render($view); }   //Add the pager $content .= theme('pager'); }   //Otherwise, show no results else { $content = "No blog posts found."; }   //Finally, we declare a block and assign it the content $block = new stdClass(); $block->title = 'Blog Posts'; $block->content = $content; return $block; }   /** * Function used for editing options on page. None needed. * @author Austin DeVinney */ function blog_post_listing_edit_form($form, &$form_state) { return $form; }

Some things to note here. We're basically making a view by hand using EntityFieldQuery. It's a nifty way to write entity queries a bit easier and comes with some useful how to's on Drupal.org. We also offload all rendering to work with Display Suite and use the built-in pagination that Drupal provides. All things considered, I'm really happy with how this comes together.

Panels

Finally, we need to add this to the page manager with panels. Browser to Structure -> Pages -> Add custom page and it will provide you with a step by step process to make a new page. All we're going to do here is add our newly created content type to the panel, as shown here.

And now, we're all ready to export to the Feature we created. Go on back to and recreate the feature and you're ready to push your code live. After everything is said and done, you should have a working blog with pagination.

.

Motivation

Obviously, this example is extremely basic. We could have done this in a View in far less time. Why would we ever want to use this? That's a great question and I'd like to elaborate on why this is important. Views are great and solve this problem just as well. They export nicely with Features and can even play with Panels (if you want to use Views as blocks or content panes). That being said, this is more for the layout of how we would have custom code that works with a lot of Drupal's best practices. Imagine instead if we have a complicated third party API we're trying to query and have our "view" react to that. What if we want a small, code-driven block that we can place discretely with panels? The use cases go on, of course.

There are many ways to solve problems in Drupal. This is just my take on a very clean and minimal code structure that allows developers to be developers and drive things with their code, rather than being stuck clicking around in menus.

Tags: drupaldrupal 7ctoolspanelsfeaturestechnologymaintainability

Dcycle: Multiple git remotes, the --depth parameter and repo size

Drupal News - January 20, 2015 - 7:31am

When building a Drupal 7 site, one oft-used technique is to keep the entire Drupal root under git (for Drupal 8 sites, I favor having the Drupal root one level up).

Starting a new project can be done by downloading an unversioned copy of D7, and initializing a git repo, like this:

Approach #1 drush dl cd drupal* git init git add . git commit -am 'initial project commit' git remote add origin ssh://me@mygit.example.com/myproject

Another trick I learned from my colleagues at the Linux Foundation is to get Drupal via git and have two origins, like this:

Approach #2 git clone --branch 7.x http://git.drupal.org/project/drupal.git drupal cd drupal git remote rename origin drupal git remote add origin ssh://me@mygit.example.com/myproject

This second approach lets you push changes to your own repo, and pull changes from the Drupal git repo. This has the advantage of keeping track of Drupal project commits, and your own project commits, in a unified git history.

git push origin 7.x git pull drupal 7.x

If you are tight for space though, there might be one inconvenience: Approach #2 keeps track of the entire Drupal 7.x commit history, for example we are now tracking in our own repo commit e829881 by natrak, on June 2, 2000:

git log |grep e829881 --after-context=4 commit e8298816587f79e090cb6e78ea17b00fae705deb Author: natrak <> Date: Fri Jun 2 18:43:11 2000 +0000 CVS drives me nuts *G*

All of this information takes disk space: Approach #2 takes 156Mb, vs. 23Mb for approach #1. This may add up if you are working on several projects, and especially if for each project you have several environments for feature branches. If you have a continuous integration server tracking multiple projects and spawning new environments for each feature branch, several gigs of disk space can be used.

If you want to streamline the size of your git repos, you might want to try the --depth option of git clone, like this:

Approach #3 git clone --branch 7.x --depth 1 http://git.drupal.org/project/drupal.git drupal cd drupal git remote rename origin drupal git remote add origin ssh://me@mygit.example.com/myproject

Adding the --depth parameter here reduces the initial size of your repo to 18Mb in my test, which interestingly is even less than approach #1. Even though your repo is now linked to the Drupal git repo, by running git log you will see that the entire history is not being stored.

Tags: blogplanet

Code Karate: An introduction to Git (part 1)

Drupal News - January 20, 2015 - 7:18am

If you are not already using Git on your Drupal websites or projects, now is the time to learn.

Drupal core announcements: Drupal 8 beta 5 on Wednesday, January 28, 2014

Drupal News - January 20, 2015 - 6:36am

The next beta for Drupal 8 will be beta 5! Here is the schedule for the beta release.

Tuesday, January 27, 2014 Only critical and major patches committed Wednesday, January 28, 2014 Drupal 8.0.0-beta5 released. Emergency commits only.

VM(doh): Be Careful with Large Select Lists on Drupal Commerce Line Item Type Configuration

Drupal News - January 19, 2015 - 2:26pm

Recently, we were debugging some performance issues with a client's Drupal Commerce website. After doing the standard optimizations, we hooked up New Relic so we could see exactly what else could be trimmed.

The site is using different line item types to differentiate between products that should be taxed in different ways. Each line item type has a field where administrators can select the tax code to use for that line item type. The options for the select list are populated via an API call to another service provider. The call for the list was using the static cache because it was thought that the list would only be populated when needed on the line item type configuration page. In reality, that's not the case.

When an Add to Cart form is displayed in Drupal Commerce, it also loads the line item type and the line item type's fields. When loading the fields, it loads all of the options even if the "Include this field on Add to Cart forms for line items of this type" option is not enabled for that field. In this case, it resulted in 90 HTTP calls to populate the list of tax codes every time someone viewed a page with an Add to Cart form.

The solution was to actually cache those results using Drupal's Cache API. You can see the improvement:

InternetDevels: The module for changing login/registration form view

Drupal News - January 19, 2015 - 2:16am

While developing a site, we have been often faced with the task of changing the way the login form (authorization unit) is displayed. Previously, in such cases a css file was used. InternetDevels team has simplified this task by creating a “Сustomize login form” module. This tool allows to change the view of the site's authorization/registration/"Forgot your password?” forms using administration tool.

Read more

Web Omelette: Creating a custom Views field in Drupal 8

Drupal News - January 19, 2015 - 12:10am

In this article I am going to show you how to create a custom Views field in Drupal 8. At the end of this tutorial, you will be able to add a new field to any node based View which will flag (by displaying a specific message) the nodes of a particular type (configurable in the field configuration). Although I will use nodes, you can use this example to create custom fields for other entities as well.

So let's get started by creating a small module called node_type_flagger (which you can also find in this repository):

node_type_flagger.info.yml:

name: Node Type Flagger description: 'Demo module that flags a particular node type in a View listing' type: module core: 8.x

In Drupal 7, whenever we want to create a custom field, filter, relationship, etc for Views, we need to implement hook_views_api() and declare the version of Views we are using. That is no longer necessary in Drupal 8. What we do now is create a file called module_name.views.inc in the root of our module and implement the views related hooks there.

To create a custom field for the node entity, we need to implement hook_views_data_alter():

node_type_flagger.views.inc:

/** * Implements hook_views_data_alter(). */ function node_type_flagger_views_data_alter(array &$data) { $data['node']['node_type_flagger'] = array( 'title' => t('Node type flagger'), 'field' => array( 'title' => t('Node type flagger'), 'help' => t('Flags a specific node type.'), 'id' => 'node_type_flagger', ), ); }

In this implementation we extend the node table definition by adding a new field called node_type_flagger. Although there are many more options you can specify here, these will be enough for our purpose. The most important thing to remember is the id key (under field) which marks the id of the views plugin that will be used to handle this field. In Drupal 7 we have instead a handler key in which we specify the class name.

In Drupal 8 we have something called plugins and many things have now been converted to plugins, including views handlers. So let's define ours inside the src/Plugin/views/field folder of our module:

src/Plugin/views/field/NodeTypeFlagger.php

<?php /** * @file * Definition of Drupal\node_type_flagger\Plugin\views\field\NodeTypeFlagger */ namespace Drupal\node_type_flagger\Plugin\views\field; use Drupal\Core\Form\FormStateInterface; use Drupal\node\Entity\NodeType; use Drupal\views\Plugin\views\field\FieldPluginBase; use Drupal\views\ResultRow; /** * Field handler to flag the node type. * * @ingroup views_field_handlers * * @ViewsField("node_type_flagger") */ class NodeTypeFlagger extends FieldPluginBase { /** * @{inheritdoc} */ public function query() { // Leave empty to avoid a query on this field. } /** * Define the available options * @return array */ protected function defineOptions() { $options = parent::defineOptions(); $options['node_type'] = array('default' => 'article'); return $options; } /** * Provide the options form. */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $types = NodeType::loadMultiple(); $options = []; foreach ($types as $key => $type) { $options[$key] = $type->label(); } $form['node_type'] = array( '#title' => $this->t('Which node type should be flagged?'), '#type' => 'select', '#default_value' => $this->options['node_type'], '#options' => $options, ); parent::buildOptionsForm($form, $form_state); } /** * @{inheritdoc} */ public function render(ResultRow $values) { $node = $values->_entity; if ($node->bundle() == $this->options['node_type']) { return $this->t('Hey, I\'m of the type: @type', array('@type' => $this->options['node_type'])); } else { return $this->t('Hey, I\'m something else.'); } } }

We are defining our NodeTypeFlagger class that extends FieldPluginBase (which is the base plugin abstract class for the views field many plugins extend from). Just above the class declaration we use the @ViewsField annotation to specify the id of this plugin (the same one we declared in the hook_views_data_alter() implementation). We also use the @ingroup annotation to mark that this is a views field handler.

In our example class, we have 4 methods (all overriding the parent class ones).

Query

First, we override the query() method but leave it empty. This is so that views does not try to include this field in the regular node table query (since the field is not backed by a table column).

DefineOptions

The second method is the defineOptions() method through which we specify what configuration options we need for this field. In our case one is enough: we need to specify the node type which we want flagged in the Views results. We set a sensible default as the article node type.

BuildOptionsForm

The third method, buildOptionsForm() is responsible for creating the form for the configuration options we declared earlier. In our case we just have a select list with which we can choose from the existing node types.

Render

Lastly, the render() method which is the most important and which deals with output. We use it to actually render the content of the field for each result. Here is where we perform some business logic based on the currently set node type option and flag with a message whether or not the current result is in fact of the type specified in the configuration.

The $resultRow object is an instance of Drupal\views\ResultRow which contains data returned for the current row by Views and the entity object at the base of the query (in our case the node). Based on this information we can perform our logic.

Keep in mind you can use depedency injection to inject all sorts of services into this class and make use of them in your logic. Additionally, you can override various other methods of the parent class in order to further customize your field.

Conclusion

There you have it. A small custom module that demonstrates how to create a custom Views field (plugin). Relationships, filters, sorters and others work in similar way. I will be covering those in later articles. Stay tuned.

DrupalOnWindows: Node Comment and Forum working together to boost user participation

Drupal News - January 18, 2015 - 10:00pm

It is frequent that customers approach us asking for help to rescue their projects from site builders. Sometimes they have technological issues (mainly slow sites) but sometimes it's just plain bad usability os some wrong marketing concepts.

We recently were asked for help from a site that gets about 5,000 unique visitors a day. Despite the not so bad visitor numbers for their niche, this page was getting very low user interaction. They barely got a handful (<10) of comments and forum posts in a whole year timespan.

Language English

Drupal core announcements: Drupal core security release window on Wednesday, January 21

Drupal News - January 18, 2015 - 9:51pm
Start:  2015-01-21 (All day) America/New_York Online meeting (eg. IRC meeting) Organizers:  David_Rothstein

The monthly security release window for Drupal 6 and Drupal 7 core will take place on Wednesday, January 21.

This does not mean that a Drupal core security release will necessarily take place on that date for either the Drupal 6 or Drupal 7 branches, only that you should prepare to look out for one (and be ready to update your Drupal sites in the event that the Drupal security team decides to make a release).

There will be no bug fix release on this date; the next window for a Drupal core bug fix release is Wednesday, February 4.

For more information on Drupal core release windows, see the documentation on release timing and security releases, and the discussion that led to this policy being implemented.

3C Web Services: Creating a Drag &amp; Drop Sorting Interface for a Drupal View

Drupal News - January 18, 2015 - 12:45pm
How to create a drag and drop sorting interface for a Drupal 7 View.

Danny Englander: Drupal Drush Segmentation Fault 11 Error: Avoiding the Rabbit Hole

Drupal News - January 18, 2015 - 12:02pm

I've been doing a lot lately with Grunt and LibSass within my drupal.org contrib theme, Gratis. Yesterday, I updated my Node modules locally. Shortly thereafter, I started getting a nasty Drush error.

line 1: 48475 Segmentation fault: 11  
/opt/local/bin/php /Users/danny/.composer/vendor/drush/drush/drush.php
--php=/opt/local/bin/php --backend=2
--root=/Users/danny/Sites/Drupal/gratis2/gratis2-site
--uri=http://default pm-updatestatus 2>&1 or sometimes just:

Segmentation fault: 11

Not only that but my local site's admin UI started WSODing. I didn't immediately connect the Node NPM update to the drush error. So I looked in my MacPorts Apache log and saw hundreds of these streaming down every few seconds:

[Sat Jan 17 13:03:56 2015] [notice] child pid 49312 exit signal Segmentation fault (11) No joy

Doing a Google search led me to some varied and vague issues with regard to Apache and MySQL but none of theme really rang true to what I was experiencing. I decided to check some of my other local sites and they all seemed fine; no errors, WSODs, or otherwise. Bizarre! I worked for about an hour, but still no joy, I was headed down a rabbit hole. That being said, I let this rest for a while. I always let a problem to sit for a bit if I can't fix it right away or ask for help. More often than not, I'll come back later and end up fixing it.

The search

I got out for some air and went to downtown San Diego to take some photos. That usually gets my mind off things and is relaxing. Arriving back later in the day, I got back into it and decided to search for drush cache clear segmentation fault theme. Bingo! (and 50 browser tabs later). I don't know why I didn't search for this earlier in the day, I was just searching the pure Apache log error which knows nothing of drush.

Sure enough it's an error related to Node modules (from the node_modules folder) having a .info file. Drush sees that and thinks it's supposed to be part of Drupal. The problem is, in a Drush world, these files are malformed. Thus the errors. Right about now, I was wishing there was some kind of .drushignore file along the same lines as .gitignore.

With this new search, here's the relevant posts I found:

In turn, these led me to the main issue, Themes should not crash when .info file appears inside node_modules

It turns out there is a proposed patch for core to prevent this error. I somehow don't see this getting in anytime soon but there are some workarounds on the Node / Grunt end of things.

Custom script

Here is the fix that I arrived at based on all the suggestions and comments in this last issue. First, we need to write a Node NPM cleanup Bash script. The script will find any .info files and rename them to .inf0 (with a zero). This will not have any negative effects as you don't commit node_modules folder to your repo and the info files are not actually needed for Grunt to run properly. So we'll call our script,npm_post.sh

#!/bin/sh
# npm_post.sh

# This script finds any .info files in the node_modules directory and renames them so they don't
# conflict with drush. package.json runs this on completion of npm install.
# These files, if any are not actually needed to run grunt and compile LIbSass
# See this issue for more info: https://www.drupal.org/node/2329453

find -L ./node_modules -type f -name "*.info" -print0 | while IFS= read -r -d '' FNAME; do
    mv -- "$FNAME" "${FNAME%.info}.inf0"
done

Once you have this in the same folder as your package.json file (in my case the root of my theme), you'll need to call it with a postinstall method from your package.json file.

  "scripts": {
    "postinstall": "sh npm_post.sh"
  },

One caveat here is that you may run into an error that the script won't run. To solve this you can either run sudo npm install --unsafe-perm or alternatively create an .npmrc file with the code:

unsafe-perm = true

and then run sudo npm install as usual.

Conclusion

Running into errors like this is definitely not fun but I learned a lot in the process. I am not sure if this is the best fix in the world but it seems to work fine for my use case. It also shows us to not get tunnel vision when trying to fix a development problem.

Tags 
  • Drupal
  • Grunt
  • Node NPM
  • Drupal Planet

Alexander Mikhailian: Data-mining Drupal users in a screenful of code

Drupal News - January 18, 2015 - 1:53am
Objective

Select like-minded users from a local community website.

Pre-requisites
  1. A Drupal website with the votingapi module enabled and at least a few dozen votes by registered users.
  2. A working installation of the R language.
Exract data

For each user, select all other users that voted on same node and comments:

SELECT v1.uid uid1, v2.uid uid2, u.name name2, v2.entity_id entity_id, v1.value value1, v2.value value2 FROM votingapi_vote v1 JOIN (votingapi_vote v2, users u) ON (v1.uid != v2.uid AND v1.entity_id=v2.entity_id AND v1.entity_type=v2.entity_type AND v2.uid=u.uid) WHERE v1.uid

This produces a table

Akshay Kalose: Drupal 8: Ajax in Forms

Drupal News - January 17, 2015 - 1:45pm

Why reload the whole page, when you can just update a certain parts of the DOM? Ajax allows you to do just this, to dynamically update content. Just one of the many great uses of Ajax is Form Validation. In this example, we will see how to implement this.

We will be making a simple form which will contain a text field that will validate if the username entered exists, and a button that will replace the text field value with a random existing username.

Building The Form

First, we need to define our two form elements:

$form['user_name'] = array( '#type' => 'textfield', '#title' => 'Username', '#description' => 'Please enter in a username', ); $form['random_user'] = array( '#type' => 'button', '#value' => 'Random Username', );

Next, to start using Ajax in Drupal, all you need to specify is the “callback“, or function to call, when the “event“, or trigger, is fired on that certain form element, in an array under the “#ajax” key:

$form['user_name'] = array( '#type' => 'textfield', '#title' => 'Username', '#description' => 'Please enter in a username', '#ajax' => array( // Function to call when event on form element triggered. 'callback' => 'Drupal\ajax_example\Form\AjaxExampleForm::usernameValidateCallback', // Javascript event to trigger Ajax. Currently for: 'onchange'. 'event' => 'change', );

In the “callback”, include the full namespaced class and function you want to call. The event can be any Javascript event without the “on”. A list of Javascript events can be found here.

Once you have added these two keys, you can add extra options such as “effect”, and “progress”. More options can be found on the Ajax API. Here are the finished elements:

$form['user_name'] = array( '#type' => 'textfield', '#title' => 'Username', '#description' => 'Please enter in a username', '#ajax' => array( // Function to call when event on form element triggered. 'callback' => 'Drupal\ajax_example\Form\AjaxExampleForm::usernameValidateCallback', // Effect when replacing content. Options: 'none' (default), 'slide', 'fade'. 'effect' => 'fade', // Javascript event to trigger Ajax. Currently for: 'onchange'. 'event' => 'change', 'progress' => array( // Graphic shown to indicate ajax. Options: 'throbber' (default), 'bar'. 'type' => 'throbber', // Message to show along progress graphic. Default: 'Please wait...'. 'message' => NULL, ), ), ); $form['random_user'] = array( '#type' => 'button', '#value' => 'Random Username', '#ajax' => array( 'callback' => 'Drupal\ajax_example\Form\AjaxExampleForm::randomUsernameCallback', 'event' => 'click', 'progress' => array( 'type' => 'throbber', 'message' => 'Getting Random Username', ), ), );

Creating The Callbacks

After creating our form elements, it is time to create the callback functions which will return the response of what to update on the page.

These callbacks will return an instance of \Drupal\Core\Ajax\AjaxResponse. Each AjaxResponse instance will contain jQuery commands that will execute on the form. You can use the “addCommand()” method on AjaxResponse to add commands that implement \Drupal\Core\Ajax\CommandInterface.

Some commands such as CssCommand and ChangedCommand did not work. Thankfully, there is InvokeCommand which allows you to run any jQuery command. You can construct it with a jQuery selector, method, and arguments:

public InvokeCommand::__construct($selector, $method, array $arguments = array())

Here are the two callbacks for our form:

public function usernameValidateCallback(array &$form, FormStateInterface $form_state) { // Instantiate an AjaxResponse Object to return. $ajax_response = new AjaxResponse(); // Check if Username exists and is not Anonymous User (''). if (user_load_by_name($form_state->getValue('user_name')) && $form_state->getValue('user_name') != false) { $text = 'User Found'; $color = 'green'; } else { $text = 'No User Found'; $color = 'red'; } // Add a command to execute on form, jQuery .html() replaces content between tags. // In this case, we replace the desription with wheter the username was found or not. $ajax_response->addCommand(new HtmlCommand('#edit-user-name--description', $text)); // CssCommand did not work. //$ajax_response->addCommand(new CssCommand('#edit-user-name--description', array('color', $color))); // Add a command, InvokeCommand, which allows for custom jQuery commands. // In this case, we alter the color of the description. $ajax_response->addCommand(new InvokeCommand('#edit-user-name--description', 'css', array('color', $color))); // Return the AjaxResponse Object. return $ajax_response; } public function randomUsernameCallback(array &$form, FormStateInterface $form_state) { // Get all User Entities. $all_users = entity_load_multiple('user'); // Remove Anonymous User. array_shift($all_users); // Pick Random User. $random_user = $all_users[array_rand($all_users)]; // Instantiate an AjaxResponse Object to return. $ajax_response = new AjaxResponse(); // ValCommand does not exist, so we can use InvokeCommand. $ajax_response->addCommand(new InvokeCommand('#edit-user-name', 'val' , array($random_user->get('name')->getString()))); // ChangedCommand did not work. //$ajax_response->addCommand(new ChangedCommand('#edit-user-name', '#edit-user-name')); // We can still invoke the change command on #edit-user-name so it triggers Ajax on that element to validate username. $ajax_response->addCommand(new InvokeCommand('#edit-user-name', 'change')); // Return the AjaxResponse Object. return $ajax_response; }

Finished Form

Here is our finished Ajax Example Form:

 

This blog post was created for Google Code-In 2014 to learn about a Drupal Core System.

Full Module Code .gist table {margin-bottom:0;}

The post Drupal 8: Ajax in Forms appeared first on Akshay Kalose.

3C Web Services: How to remove the Fieldset from a Drupal Address Field

Drupal News - January 17, 2015 - 7:57am

INTRODUCTION

The Drupal Address Field Module is a great tool that we use often. There are, however, many times when the default output causes some issues for us. Be default, Address Field places all of its individual field components inside of a Feldset wrapper. This is usually a nice feature but there are times when you may want to remove this Fieldset wrapper for ascetics. Or, perhaps, you'd like to place additional fields within the Address Field's Fieldset. We'll show you how to do both.

DrupalOnWindows: Node Comments and Forums working together to boost user engagement

Drupal News - January 17, 2015 - 4:07am

It is frequent that customers approach us asking for help to rescue their projects from site builders. Sometimes they have technological issues (mainly slow sites) but sometimes it's just plain bad usability os some wrong marketing concepts.

We recently were asked for help from a site that gets about 5,000 unique visitors a day. Despite the not so bad visitor numbers for their niche, this page was getting very low user interaction. They barely got a handful (<10) of comments and forum posts in a whole year timespan.

Language English

The Cherry Hill Company: Creating a Context Plugin

Drupal News - January 16, 2015 - 1:49pm

On a recent project I was using the combination of Field Collection, Entity Reference, Taxonomy Terms, and Context to make a reusable set of references to terms on various content types. Then, based on the referenced term, I wanted to satisfy a context condition.

Due to the somewhat complex structure, the context was not aware of the term referenced through entity reference and the field collection.

In a case like this, creating a custom context plugin was a good solution.

I got started by reading a couple of helpful posts by others: Custom Context Conditions and Extending Drupal's Context Module: Custom...

Read more »

Advomatic: Views in Drupal 8: Improved Displays

Drupal News - January 16, 2015 - 11:09am
Now that Drupal 8 is in beta, I’ve been trying to spend some more time with it. Reading articles and watching presentations are good ways to keep up with where things are (or are going), but nothing beats actually using it. Simplytest.me, Pantheon, and Acquia Cloud all now provide free ways to spin up an instance... Read more »
Syndicate content