Answers.Body: <p>Have you tried the <a href="https://docs.craftcms.com/api/v3/craft-base-element.html#method-isfielddirty" rel="nofollow noreferrer"><code>$element-&gt;isFieldDirty()</code></a> method, or checking through the <a href="https://docs.craftcms.com/api/v3/craft-base-element.html#dirtyfields" rel="nofollow noreferrer"><code>$element-&gt;dirtyFields</code></a> array for your asset field, rather than checking revision dates?</p>
  <p>There may be a good reason why you're not using those, but I thought I'd suggest it in case you hadn't considered it.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-05T19:06:34.007Z
Answers.Text: I appreciate the suggestion, and this does seem to consistently tell me that the asset field has changed. But we need details about the asset itself which I don't think we can get via dirtyFields.
Answers.UserDisplayName: plaintxt
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-05T20:38:31.783Z
Answers.Text: I decided to flag this as the correct answer because $element-dirtyFields does reliably tell me whether the Custom Image has been updated during the save cycle. I can then use $entry->customImage->one(), which will either return null (image removed) or an AssetQuery that I can use to get the detailed info we need. Thanks!
Answers.UserDisplayName: plaintxt
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-02-17T17:56:20.563Z
Answers.Text: Sorry to hijack, `isFieldDirty` only works for custom fields, is there an equivalent for `title` or `status` do you know? Thanks
Answers.UserDisplayName: iamkeir
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-02-17T18:04:12.843Z
Answers.Text: Answered my own question, yes, `$element->isAttributeDirty('title')`... :)
Answers.UserDisplayName: iamkeir
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-02-18T13:38:03.940Z
Answers.Text: Gah...`isAttributeDirty` and `isFieldDirty` return inconsistent/inaccurate responses when used with `EVENT_ON_SAVE`... https://craftcms.stackexchange.com/questions/39066/check-if-element-status-has-changed-on-event-before-save
Answers.UserDisplayName: iamkeir
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-05-05T10:25:20.143Z
Answers.LastActivityDate: 2021-05-05T10:25:20.143Z
Answers.UserDisplayName: Wallace
Body: <p>We need to send a notification email when an entry's asset field, Custom Image, has been updated on entry save. We're able to do this consistently for text fields but I'm having trouble doing the same for an asset field.</p>
  <pre><code>// Use statements etc
  
  ...
  
  // Register the event handler
  Event::on(Entry::class, Entry::EVENT_AFTER_SAVE, [$this, 'handleAfterSave']);
  
  ...
  
  public function handleAfterSave(ModelEvent $event): void
  {
      $entry = $event-&gt;sender;
      $revisions = Entry::find()-&gt;revisionOf($entry)-&gt;status(null)-&gt;orderBy('revisionId DESC')-&gt;all();
      $lastRevision = Craft::$app-&gt;getElements()-&gt;getElementById($revisions[1]-&gt;id);
  
      $fields = Craft::$app-&gt;getFields();
      
      // text fields
      $notificationHandles = [
          'textField1',
          'textField2',
      ];
      $updatedFields = array_map(
          fn ($h) =&gt; [
              'fieldName' =&gt; $fields-&gt;getFieldByHandle($h)-&gt;name,
              'oldValue' =&gt; $lastRevision[$h],
              'newValue' =&gt; $entry[$h],
          ],
          // Only need to show field if different from last revision
          array_filter($notificationHandles, fn ($h) =&gt; $lastRevision[$h] !== $entry[$h])
      );
      
      if (count($updatedFields) &gt; 0) {
          self::$notifications-&gt;notifyUpdated($entry, $updatedFields);
      }
  }
  </code></pre>
  <p>The above works for text fields. However, when adapting for an asset field, it appears that <code>$lastRevision[$h]</code> is not immediately updated.</p>
  <p>If we have an entry with an empty Custom Image asset field:</p>
  <ol>
  <li>Assign an image to Custom Image</li>
  <li>Save</li>
  <li>Email is sent</li>
  <li>Return to the entry</li>
  <li>Remove the asset from Custom Image</li>
  <li>Save</li>
  <li>No email is sent</li>
  </ol>
  <p>To put it another way, if I have an entry with an empty Custom Image field:</p>
  <ol>
  <li>Assign an image to Custom Image</li>
  <li>Save</li>
  <li>Email is sent</li>
  <li>Return to the entry</li>
  <li>Remove the asset from Custom Image</li>
  <li>Save, but dump <code>$lastRevision</code> using <code>EVENT_AFTER_SAVE</code></li>
  <li>We can see that <code>customImage</code> is still <code>null</code>, where I would expect it to show the previously attached image (an AssetQuery etc)</li>
  <li>No email is sent because both <code>$lastRevision['customImage']</code> and <code>$entry['customImage']</code> are <code>null</code>.</li>
  </ol>
  <p>Thanks!</p>
  
Tags: <craft3><assets><events>
Title: How would I detect whether an entry's asset field has been updated on save?
ThreadText: # How would I detect whether an entry's asset field has been updated on save?
  
  (Asked by: username_0 on 2021-05-04)
  
  We need to send a notification email when an entry's asset field, Custom Image, has been updated on entry save. We're able to do this consistently for text fields but I'm having trouble doing the same for an asset field.
  
  ```
  // Use statements etc
  
  ...
  
  // Register the event handler
  Event::on(Entry::class, Entry::EVENT_AFTER_SAVE, [$this, 'handleAfterSave']);
  
  ...
  
  public function handleAfterSave(ModelEvent $event): void
  {
      $entry = $event->sender;
      $revisions = Entry::find()->revisionOf($entry)->status(null)->orderBy('revisionId DESC')->all();
      $lastRevision = Craft::$app->getElements()->getElementById($revisions[1]->id);
  
      $fields = Craft::$app->getFields();
      
      // text fields
      $notificationHandles = [
          'textField1',
          'textField2',
      ];
      $updatedFields = array_map(
          fn ($h) => [
              'fieldName' => $fields->getFieldByHandle($h)->name,
              'oldValue' => $lastRevision[$h],
              'newValue' => $entry[$h],
          ],
          // Only need to show field if different from last revision
          array_filter($notificationHandles, fn ($h) => $lastRevision[$h] !== $entry[$h])
      );
      
      if (count($updatedFields) > 0) {
          self::$notifications->notifyUpdated($entry, $updatedFields);
      }
  }
  
  ```
  
  The above works for text fields. However, when adapting for an asset field, it appears that `$lastRevision[$h]` is not immediately updated.
  
  If we have an entry with an empty Custom Image asset field:
  
  1. Assign an image to Custom Image
  2. Save
  3. Email is sent
  4. Return to the entry
  5. Remove the asset from Custom Image
  6. Save
  7. No email is sent
  
  To put it another way, if I have an entry with an empty Custom Image field:
  
  1. Assign an image to Custom Image
  2. Save
  3. Email is sent
  4. Return to the entry
  5. Remove the asset from Custom Image
  6. Save, but dump `$lastRevision` using `EVENT_AFTER_SAVE`
  7. We can see that `customImage` is still `null`, where I would expect it to show the previously attached image (an AssetQuery etc)
  8. No email is sent because both `$lastRevision['customImage']` and `$entry['customImage']` are `null`.
  
  Thanks!
  
  **Tags:** craft3, assets, events
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2021-05-05. Score: 2 | Accepted answer
  
  Have you tried the [`$element->isFieldDirty()`](https://docs.craftcms.com/api/v3/craft-base-element.html#method-isfielddirty) method, or checking through the [`$element->dirtyFields`](https://docs.craftcms.com/api/v3/craft-base-element.html#dirtyfields) array for your asset field, rather than checking revision dates?
  
  There may be a good reason why you're not using those, but I thought I'd suggest it in case you hadn't considered it.
  
  > **Comments:**
  > **username_0**: I appreciate the suggestion, and this does seem to consistently tell me that the asset field has changed. But we need details about the asset itself which I don't think we can get via dirtyFields.  
  > **username_0**: I decided to flag this as the correct answer because $element-dirtyFields does reliably tell me whether the Custom Image has been updated during the save cycle. I can then use $entry->customImage->one(), which will either return null (image removed) or an AssetQuery that I can use to get the detailed info we need. Thanks!  
  > **username_2**: Sorry to hijack, `isFieldDirty` only works for custom fields, is there an equivalent for `title` or `status` do you know? Thanks  
  > **username_2**: Answered my own question, yes, `$element->isAttributeDirty('title')`... :)  
  > **username_2**: Gah...`isAttributeDirty` and `isFieldDirty` return inconsistent/inaccurate responses when used with `EVENT_ON_SAVE`... https://craftcms.stackexchange.com/questions/39066/check-if-element-status-has-changed-on-event-before-save  
  
  ---
  
  