How to programmatically set the field formatter for a field given certain conditions I have an entity 'house' with an address field. The address field comes with a default field formatter plugin. This is perfect for when i view my entity at its canonical route and where its view_mode is 'full'.
However I want to change how the address field is displayed when the 'house' has view_mode 'teaser'. For example at a page that displays a list of all my houses. To be specific I want my address to appear on one line.
Now, I have gotten all this working. Like this:
house_entity/src/Plugin/Field/FieldFormatter/AddressTeaserFormatter
&lt;?php

namespace Drupal\rrre_entities\Plugin\Field\FieldFormatter;

use Drupal\address\Plugin\Field\FieldFormatter\AddressPlainFormatter;
use Drupal\Core\Field\FieldItemListInterface;

/**
 * Plugin implementation of the 'address_teaser' formatter.
 *
 * @FieldFormatter(
 *   id = &quot;address_teaser&quot;,
 *   label = @Translation(&quot;Teaser&quot;),
 *   field_types = {
 *     &quot;address&quot;,
 *   },
 * )
 */
class AddressTeaserFormatter extends AddressPlainFormatter {

  /**
   * {@inheritdoc}
   */
public function viewElements(FieldItemListInterface $items, $langcode) {
  $elements = parent::viewElements($items, $langcode);
  foreach ($elements as &amp;$element) {
    $element['#theme'] = 'address_teaser';
  }
  return $elements;
}

house_entity/house_entity.module
/**
 * Implements hook_theme().
 */
function house_entity_theme($existing, $type, $theme, $path) {
  return [

    'house' =&gt; [
      'render element' =&gt; 'listing',
    ],

    'address_teaser' =&gt; [
      'variables' =&gt; [
        'recipient' =&gt; '',
        'organization' =&gt; '',
        'address_line1' =&gt; '',
        'address_line2' =&gt; '',
        'postal_code' =&gt; '',
        'sorting_code' =&gt; '',
        'dependent_locality' =&gt; [],
        'locality' =&gt; [],
        'administrative_area' =&gt; [],
        'country' =&gt; [],
      ],
    ],
  ];
}

and in the same house_entity.module file:
/**
 * Implements template_preprocess_HOOK().
 */
function template_preprocess_house(&amp;$variables) {
  $addressDisplayOptions = [
    'type' =&gt; 'address_teaser',
  ];
  $house-&gt;address-&gt;getItemDefinition()-&gt;getFieldDefinition()-&gt;setDisplayOptions('view', $addressDisplayOptions);
}

Finally I have my template for my new address fieldformatter all set up at house_entity/templates/address-teaser.htm.twig
This all works fine.
Except that the custom field formatter does not apply to the first 'house' in my list of 'houses' (it does apply to all subsequent 'houses') ... and adding a xdebug_break() immediately after the line:
$listing-&gt;address-&gt;getItemDefinition()-&gt;getFieldDefinition()-&gt;setDisplayOptions('view', $addressDisplayOptions);
Triggers the following error - basically that the twig template was not found:

Question?:
Do I have my template in the right place?
Is there a more convenient way of setting a field formatter for a particular field on an entity?
Is there a more convenient way of setting a field formatter for a particular field on an entity?


Yes, choose the formatter in the view mode settings (configure in the user interface) rather than using template preprocess.

(I found this old question looking for how to make a field formatter, and ended up copying Drupal\user\Plugin\Field\FieldFormatter and simplifying it by dropping the configuration parts, and then simply selecting that formatter on the view modes and Views tables i wanted to use it on.)

For ensuring this formatter doesn't show up in places it shouldn't, the key part is "isApplicable"; here's what mine looked like for a custom entity 'give_donation' and a field named 'recurring':

  /**
   * {@inheritdoc}
   */
  public static function isApplicable(FieldDefinitionInterface $field_definition) {
    return $field_definition-&gt;getTargetEntityTypeId() === 'give_donation' &amp;&amp; $field_definition-&gt;getName() === 'recurring';
  }