New blog post about CiviCRM mailing

This commit is contained in:
c v t 2019-08-31 22:34:31 +02:00
parent 5832ee4b12
commit 3fce3c1a7a
3 changed files with 107 additions and 0 deletions

View File

@ -0,0 +1,107 @@
---
layout: post
title: CiviCRM AngularJS extension
description: Adding custom validation to the CiviCRM Mailing form
image: civicrm_validation_header.jpg
category: howto
date: 2019-08-30
---
A couple of our clients use [CiviCRM](https://civicrm.org/); one of them uses
the "Mailing" features to send out emails to their supporters. Apparently,
they're facing a bug where if someone sends out a Mailing with the same name
(not subject line, just the internal identifier 🙄) as an existing one, it'll
freeze the CRM later.
As an added challenge, the Mailings feature of CiviCRM [now uses
AngularJS](https://docs.civicrm.org/dev/en/latest/framework/angular/) following
a recent rebuild, and there aren't many tutorials or examples out there.
Luckily, the CiviCRM developer community was super-helpful, and we managed to
sort out some in-form validation to prevent duplicate Mailing
names for our client… and now for you, too!
## Create a new extension
Using [`civix`](https://github.com/totten/civix), we set up a new CiviCRM extension for our code:
civix generate:module mailing
(We called our extension `mailing`, because our creative director was occupied with an Art at the time)
Our client sensibly keeps their custom CiviCRM extensions in `git`, at this stage we initialised a repository, added the boilerplate template code, and pushed.
## Set up the AngularJS hook
A function called `mailing_civicrm_alterAngular()` will get executed whenever an AngularJS page loads, and you can use a `ChangeSet` to edit an AngularJS template and, because AngularJS templates specify form logic, also change the validation behaviour. Our hook function looks like this:
function mailing_civicrm_alterAngular($angular) {
$changeSet = \Civi\Angular\ChangeSet::create('mailing_name_unique')
->alterHtml('~/crmMailing/BlockSummary.html', function(phpQueryObject $doc) {
// name validation
$doc->find('.crm-group:has([crm-ui-id="subform.mailingName"])')->attr('ng-controller', 'NameValidateCtrl');
$doc->find('[crm-ui-id="subform.mailingName"]')->attr('ng-blur', 'validateName(mailing, \'name\')');
$doc->find('[crm-ui-id="subform.mailingName"]')->attr('crm-ui-validate', 'isValid');
});
$angular->add($changeSet);
CRM_Core_Resources::singleton()->addScriptFile('mailing', 'js/disallow-duplicate-names.js');
}
Setting `crm-ui-validate` to `validateName` directly fired the event _way_ too many times, so instead `validateName` is only called when focus leaves the field, `ng-blur`, which then sets the `isValid` variable that's checked by `crm-ui-validate`.
## Create the `validateName` function
Then, the code which queries the CiviCRM API to check for mailings with duplicate names:
var validating = false;
(function(angular, $) {
var crmMailing = angular.module('crmMailing');
crmMailing.controller('NameValidateCtrl', function($scope) {
$scope.isValid = false;
$scope.validateName = function(mailing, field) {
if (!validating) {
validating = true;
CRM.api3('Mailing', 'get', {
"sequential": 1,
"name": mailing[field],
"id": {"!=": mailing.id}
}).then(function(result) {
// do something with result
if (result.count > 0 ) {
$scope.isValid = false;
CRM.alert(ts('There is already a mailing with this name; sending this one will crash CiviCRM!'));
} else {
$scope.isValid = true;
}
}, function(error) {
// oops
console.log(error);
});
validating = false;
}
};
});
})(angular, CRM.$);
(saved as `js/disallow-duplicate-names.js`)
## Conclusion
Activate the extension, e.g. with `cv`
$ cv en mailing
Now, open a mailing and try to give it the same name as an existing one you should see the field border turn red, and you'll be prevented from continuing or sending the mailing:
![](/assets/images/civicrm_validation.png)
(As a bonus, the extension also sends a notification to the user using `CRM.alert` to explain the error)
It does seem like a red border sometimes hangs around the field label even after the value is valid again.. but apart from that, the feature is working great!

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB