Hi everyone,

I am trying to achieve a specific conditional behavior on a node page using only the Views UI (without custom modules or custom PHP code).

My Setup

I have two content types:

  1. Request (richieste_tenute_meccaniche)

  2. Quote (preventivo_tenute_meccaniche)

The Quote content type contains an Entity Reference field named field_riferimento_richiesta_tenu which points to the Request content type.

The Goal

When a user visits a Request node page, a block View needs to check if the current logged-in user has already submitted a quote for that specific request.

  • Case A (No quote submitted yet): If the current user has not created a Quote node for this Request, show a button/link: "INSERISCI UN PREVENTIVO PER QUESTA RICHIESTA".

    • This link points to /node/add/preventivo_tenute_meccaniche?field_riferimento_richiesta_tenu=[node:nid] to prepopulate the entity reference field via query string.

  • Case B (Quote already submitted): Each user is allowed to submit only one quote per request. If the current user has already created a Quote node referencing this specific Request, the button must disappear. In its place, a text message must be displayed: "HAI GIA’ INVIATO UN PREVENTIVO PER QUESTA RICHIESTA".

What I have done so far

I created a Block View showing Request content:

  • Filter Criteria: Content type = Request (richieste_tenute_meccaniche)

  • Contextual Filter: Content: ID (configured to "Provide default value -> Content ID from URL")

My Question

How can I configure the Relationships, Contextual Filters, or No Results Behavior inside the Views UI to check for the existence of a Quote node belonging to the current logged-in user for the current Request node?

Should the View query the Request content type (as I did) and reverse-relate the Quote, or is it better to base the View on the Quote content type and use the "No Results Behavior" to render the link when no quote is found?

Any detailed step-by-step guidance on how to set up these specific Relationships and Filters would be greatly appreciated!

Thanks in advance!

Comments

linux56’s picture

Following up on my previous post where I was struggling to pass the current Request ID to a prepopulated form when a View returns no results—I finally solved it! After days of fighting with missing row tokens and URL aliases, here is the clean, definitive solution.

Why the usual methods failed:

  1. No Row Tokens: Since the View is empty (zero results), Drupal doesn't generate any tokens for fields.

  2. No Contextual Filters: If your View architecture doesn't use contextual filters, Twig variables like {{ view.args }} remain completely empty.

  3. URL Aliases: If your site uses clean URLs (e.g., /requests/my-test-title), a basic browser JavaScript regex looking for /node/ID fails because the actual ID is hidden.

The Solution

Instead of forcing Drupal to look for server-side tokens, we can solve this entirely on the client side (in the user's browser). We can insert a small HTML + Vanilla JavaScript snippet inside a Global: Text area under the No Results Behavior of the View.

Crucial step: Make sure the Text format under the text area is set to Full HTML, otherwise Drupal will strip out the <script> tags.

The script bypasses the visible URL and directly queries Drupal’s global system object window.drupalSettings (or falls back to the <link rel="shortlink"> tag in the page HEAD). It extracts the raw numeric Node ID, cleans it, and injects it straight into the button link.

The Code

Paste this directly into your View's No Results Text Area:

HTML

<div class="blocco-inserimento-bottone" style="margin: 20px 0;">
  <a id="bottone-preventivo-dinamico" href="/node/add/preventivo_tenute_meccaniche?richiesta=" class="button button--primary" style="display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; text-decoration: none; border-radius: 4px; font-weight: bold;">
    ADD A QUOTE FOR THIS REQUEST
  </a>
</div>

<script>
  (function() {
    var nid = '';

    // 1. Check Drupal's global path settings (works perfectly with URL Aliases)
    if (window.drupalSettings && window.drupalSettings.path && window.drupalSettings.path.currentPath) {
      var percorso = window.drupalSettings.path.currentPath; // Returns e.g., "node/307"
      var estraiNumeri = percorso.match(/\d+/);
      if (estraiNumeri) {
        nid = estraiNumeri[0]; // Isolates only the digits (e.g., "307")
      }
    }

    // 2. Fallback: check the HTML shortlink in the HEAD if the first method fails
    if (!nid) {
      var tagShortlink = document.querySelector('link[rel="shortlink"]');
      if (tagShortlink) {
        var href = tagShortlink.getAttribute('href');
        var estraiNumeriHref = href.match(/\d+/);
        if (estraiNumeriHref) {
          nid = estraiNumeriHref[0];
        }
      }
    }

    // 3. Inject the clean numeric ID into the button's href attribute
    if (nid) {
      var elementoBottone = document.getElementById('bottone-preventivo-dinamico');
      if (elementoBottone) {
        elementoBottone.href = "/node/add/preventivo_tenute_meccaniche?richiesta=" + nid;
      }
    }
  })();
</script>

Why this is the best approach:

  • Zero Server Overhead: It doesn't trigger extra database queries or heavy token modules.

  • Alias-Proof: It works seamlessly whether your path is a raw system path (/node/307) or a customized semantic alias (/quotes/industrial-seal-maintenance).

  • Clean Data Input: By using match(/\d+/), it strips out any trailing text or duplicates (avoiding buggy strings like node/307,307), ensuring your entity prepopulate module receives a flawless, clean integer.

Hopefully, this saves someone else from the headache I went through!

ressa’s picture

Great that you solved it! There are so many ways to create a solution in Drupal, so thanks for sharing it in detail. Have a nice day.