0

HTML-Ansicht: Klick auf Kachel soll Datensatz öffnen (ui.popupRecord reagiert nicht)

Hallo zusammen,

ich habe mir in einer Formel eine HTML-Historie gebaut, um vergangene Chargen/Datensätze übersichtlich als scrollbare Liste darzustellen. Das funktioniert visuell und vom Scrolling her auch wunderbar (siehe Screenshot).

Mein Problem: Ich schaffe es einfach nicht, die einzelnen Kacheln klickbar zu machen, um den verknüpften Datensatz zu öffnen. Ich beisse mir hier gerade die Zähne aus.

Das Szenario:

  • Umgebung: Ninox Private Cloud.

  • Element: Berechnungsfeld (Formel) mit html(...).

  • Ziel: Klick auf ein <div> oder <button> innerhalb des HTMLs soll den entsprechenden Datensatz öffnen.

Was ich schon versucht habe: Ich weiss, dass openRecord() im HTML-Kontext nicht funktioniert und man stattdessen ui.popupRecord('ID') nutzen muss. Ich habe diverse Varianten durchprobiert:

  1. Klassisches onclick="ui.popupRecord('ID')" in einem <div>.

  2. Nutzung von <button> Elementen.

  3. Nutzung von <a> Tags mit href="javascript:ui.popupRecord(...)".

  4. Diverse Escaping-Varianten für die Anführungszeichen (einfache, doppelte, maskierte), um Syntaxfehler zu vermeiden.

Der Code läuft ohne Fehlermeldung, die Liste wird angezeigt, aber der Klick wird vom Browser/Ninox einfach ignoriert oder nicht ausgeführt.
 

// ... (vorherige Berechnungen) ...

let myId := text(i);

// Versuch mit Button und Platzhalter-Replace gegen Syntax-Fehler
let myTemplate := "
<button class='h-btn' onclick='ui.popupRecord(""PLATZHALTER"")'>
   <div class='h-content'>
      </div>
</button>";

let s1 := replace(myTemplate, "PLATZHALTER", myId);
// ...

Hat jemand einen Tipp, wie man in der Private Cloud sicher einen openRecord-Befehl aus einem HTML-Feld abfeuert? Gibt es da eine spezielle Syntax oder Restriktionen bei Inline-Javascript?

Vielen Dank für eure Unterstützung!

Stephan

5 Antworten

null
    • Pushing the Boundaries of Ninox
    • Gotje_Ing
    • gestern
    • Gemeldet - anzeigen

    Moin,

     

    ich habe eine sehr ähnliche Anfrage gerade hier beantwortet:
    https://forum.ninox.de/t/h7ypbh7/openfullscreen-in-formel
    Wenn du trotzdem nicht weiterkommst, sag nochmal Bescheid.

      • Rafael_Sanchis
      • vor 12 Stunden
      • Gemeldet - anzeigen

       

      Hi GötJe.

      I have some similar script but not work for me, I don't know why

      let selectedProject := Project;
      let rawList := (select 'History Version' where Project = selectedProject);
      let versions := (rawList order by Version_Number);
      let sortedList := for i in range(cnt(versions), 0, -1) do
              item(versions, i - 1)
          end;
      let vCount := cnt(sortedList);
      if vCount = 0 then
          html("<div style='padding:10px; color:grey; font-family:sans-serif;'>No version history found.</div>")
      else
          let css := "
          <style>
              .v-main {
                  font-family: -apple-system, BlinkMacSystemFont, sans-serif;
                  width: 100%;
                  padding: 10px;
              }
              .v-header {
                  font-size: 11px;
                  font-weight: 700;
                  color: #6366f1;
                  margin-bottom: 12px;
                  display: flex;
                  justify-content: space-between;
                  text-transform: uppercase;
                  letter-spacing: 0.5px;
              }
              .v-card {
                  display: block;
                  width: 100%;
                  background: #fff;
                  border: 1px solid #e5e7eb;
                  border-left: 4px solid #d1d5db;
                  border-radius: 8px;
                  margin-bottom: 10px;
                  padding: 12px;
                  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
                  text-align: left;
                  cursor: pointer;
                  position: relative;
                  transition: all 0.2s;
              }
              .v-card:hover {
                  background-color: #f9fafb;
                  border-color: #d1d5db;
                  box-shadow: 0 2px 6px rgba(0,0,0,0.08);
              }
              .v-card:active {
                  background-color: #f3f4f6;
                  border-left-color: #6366f1;
              }
              .v-card.major { border-left-color: #dc2626; }
              .v-card.minor { border-left-color: #f59e0b; }
              .v-card.patch { border-left-color: #10b981; }
      
              .v-content { pointer-events: none; }
              .v-row {
                  display: flex;
                  justify-content: space-between;
                  align-items: center;
                  margin-bottom: 6px;
              }
              .v-version {
                  font-size: 16px;
                  font-weight: 700;
                  color: #111827;
                  font-family: 'SF Mono', Monaco, monospace;
              }
              .v-date {
                  font-size: 11px;
                  color: #6b7280;
              }
              .v-type {
                  font-size: 10px;
                  font-weight: 600;
                  padding: 3px 8px;
                  border-radius: 4px;
                  text-transform: uppercase;
                  display: inline-block;
              }
              .v-type.major { background: #fee2e2; color: #dc2626; }
              .v-type.minor { background: #fef3c7; color: #d97706; }
              .v-type.patch { background: #d1fae5; color: #059669; }
      
              .v-impact {
                  font-size: 10px;
                  font-weight: 600;
                  padding: 3px 8px;
                  border-radius: 4px;
                  display: inline-block;
                  margin-left: 4px;
              }
              .v-impact.critical { background: #fecaca; color: #991b1b; }
              .v-impact.high { background: #fed7aa; color: #c2410c; }
              .v-impact.medium { background: #fde68a; color: #a16207; }
              .v-impact.low { background: #d1fae5; color: #065f46; }
      
              .v-change {
                  font-size: 12px;
                  color: #374151;
                  margin-top: 6px;
                  line-height: 1.4;
              }
              .v-meta {
                  display: flex;
                  gap: 12px;
                  margin-top: 8px;
                  font-size: 11px;
                  color: #6b7280;
              }
              .v-meta-item {
                  display: flex;
                  align-items: center;
                  gap: 4px;
              }
              .v-status {
                  font-size: 10px;
                  font-weight: 600;
                  padding: 2px 6px;
                  border-radius: 3px;
              }
              .v-status.passed { background: #d1fae5; color: #065f46; }
              .v-status.failed { background: #fee2e2; color: #991b1b; }
              .v-status.nottested { background: #f3f4f6; color: #6b7280; }
      
              .v-icon { font-size: 14px; }
          </style>";
          let htmlCards := for rec in sortedList do
                  let vNumber := rec.Version_Number;
                  let vType := lower(text(rec.Type_Version));
                  let vImpact := lower(text(rec.Impact_Level));
                  let vChange := text(rec.Change_Type);
                  let vDate := format(rec.Saved_Date_Time, "DD MMM YYYY, HH:mm");
                  let vTesting := text(rec.Testing_Status);
                  let vAffected := text(rec.Affected_Tables);
                  let vCreator := text(rec.Created_By);
                  let myId := text(rec);
                  let statusClass := if vTesting = "Passed" then
                          "passed"
                      else
                          if vTesting = "Failed" then "failed" else "nottested" end
                      end;
                  let impactClass := if vImpact = "critical" then
                          "critical"
                      else
                          if vImpact = "high" then
                              "high"
                          else
                              if vImpact = "medium" then "medium" else "low" end
                          end
                      end;
                  let typeIcon := if vType = "major" then
                          "🔴"
                      else
                          if vType = "minor" then "🟡" else "🟢" end
                      end;
                  let tpl := "
              <button type='button' class='v-card TYPE_CLASS' onclick='ui.popupRecord(""ID_PH"")'>
                  <div class='v-content'>
                      <div class='v-row'>
                          <div>
                              <span class='v-icon'>ICON_PH</span>
                              <span class='v-version'>v-VERSION_PH</span>
                          </div>
                          <span class='v-date'>DATE_PH</span>
                      </div>
                      <div class='v-row'>
                          <div>
                              <span class='v-type TYPE_CLASS'>TYPE_PH</span>
                              <span class='v-impact IMPACT_CLASS'>IMPACT_PH</span>
                          </div>
                          <span class='v-status STATUS_CLASS'>STATUS_PH</span>
                      </div>
                      <div class='v-change'>📝 CHANGE_TYPE_PH</div>
                      <div class='v-meta'>
                          <div class='v-meta-item'>📦 AFFECTED_PH</div>
                          <div class='v-meta-item'>👤 CREATOR_PH</div>
                      </div>
                  </div>
              </button>";
                  let s1 := replace(tpl, "ID_PH", myId);
                  let s2 := replace(s1, "VERSION_PH", vNumber);
                  let s3 := replace(s2, "DATE_PH", vDate);
                  let s4 := replace(s3, "TYPE_PH", vType);
                  let s5 := replace(s4, "TYPE_CLASS", vType);
                  let s6 := replace(s5, "IMPACT_PH", vImpact);
                  let s7 := replace(s6, "IMPACT_CLASS", impactClass);
                  let s8 := replace(s7, "CHANGE_TYPE_PH", vChange);
                  let s9 := replace(s8, "STATUS_PH", vTesting);
                  let s10 := replace(s9, "STATUS_CLASS", statusClass);
                  let s11 := replace(s10, "AFFECTED_PH", vAffected);
                  let s12 := replace(s11, "CREATOR_PH", vCreator);
                  replace(s12, "ICON_PH", typeIcon)
              end;
          let vMajor := cnt(sortedList[Type_Version = "Major"]);
          let vMinor := cnt(sortedList[Type_Version = "Minor"]);
          let vPatch := cnt(sortedList[Type_Version = "Patch"]);
          html(css + "<div class='v-main'>" + "<div class='v-header'>" + "<span>Version History (" +
          vCount +
          ")</span>" +
          "<span>🔴 " +
          vMajor +
          " | 🟡 " +
          vMinor +
          " | 🟢 " +
          vPatch +
          "</span>" +
          "</div>" +
          join(htmlCards, "") +
          "</div>")
      end
      
      • Pushing the Boundaries of Ninox
      • Gotje_Ing
      • vor 12 Stunden
      • Gemeldet - anzeigen

       Please try to replace the following line:
       

      let myId := text(rec);

      with this 
       

      let myId := raw(rec.Nr);

      Alternatively, use string(rec) instead of text(rec).
      text() gives "5", string() or raw() gives "A5". 

      • Rafael_Sanchis
      • vor 11 Stunden
      • Gemeldet - anzeigen

       

      Thanks a lot Götje appreciate you help now work

      my dashboard

    • Stephan_S
    • vor 15 Stunden
    • Gemeldet - anzeigen

    Salü

    Danke dir für den Link – der hat mir als Ausgangspunkt auf jeden Fall weitergeholfen. Nach einigem Herumprobieren und mit Unterstützung von KI habe ich es schliesslich geschafft, die Datensätze so einzubinden, dass sie nun über die einzelnen Kacheln direkt angesprochen und geöffnet werden können.

    Hier der vollstaendige Code, den ich aktuell verwende. Vielleicht ist er ja auch für andere hilfreich:

    let myArt := Artikel.Artikelnummer;
    let myRoom := Konfektionierungsraum;
    let mySize := Artikel.Bezeichnung2;
    let rawList := (select Chargenreport
            where Artikel.Artikelnummer = myArt and Konfektionierungsraum = myRoom and
                            Artikel.Bezeichnung2 = mySize and
                        'Datensatz verworfen' != true and
                    'Erfassung abgeschlossen' = true and
                Status_Filter = "Ok" and
            'Status Statisik' = "Ok");
    let relatedRecords := rsort(rawList order by _HF_StoppDatumGesamt);
    let vCount := cnt(relatedRecords);
    if vCount = 0 then
        html("<div style='padding:10px; color:grey; font-family:sans-serif;'>Keine Historie gefunden.</div>")
    else
        let vAllOut := relatedRecords._HF_OutputProMinute;
        let vGlobalAvg := if avg(vAllOut) = null then 0 else avg(vAllOut) end;
        let css := "
        <style>
            .h-main { font-family: -apple-system, BlinkMacSystemFont, sans-serif; width: 100%; }
            .h-header { font-size: 10px; font-weight: 700; color: #9ca3af; margin-bottom: 8px; display: flex; justify-content: space-between; text-transform: uppercase; }
            .h-btn {
                display: block; width: 100%;
                background: #fff; border: 1px solid #e5e7eb; border-radius: 6px;
                margin-bottom: 6px; padding: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.03);
                text-align: left; cursor: pointer; position: relative;
            }
            .h-btn:hover { background-color: #f9fafb; border-color: #d1d5db; }
            .h-btn:active { background-color: #f3f4f6; border-color: #3b82f6; }
            .h-content { pointer-events: none; }
            .h-row { display: flex; justify-content: space-between; margin-bottom: 4px; }
            .txt-head { font-size: 11px; font-weight: 600; color: #374151; }
            .txt-sub  { font-size: 11px; color: #6b7280; }
    
            /* SAFARI FIX: Feste Höhe, font-size 0 */
            .bar-bg { width: 100%; height: 6px; background: #f3f4f6; border-radius: 3px; display: flex; overflow: hidden; margin-top: 4px; font-size: 0px; }
            .bar-seg { height: 100%; display: inline-block; }
        </style>";
        let htmlCards := for i in relatedRecords do
                let vSetup := if i._HF_EinrichtDauerStunden = null then
                        0
                    else
                        number(i._HF_EinrichtDauerStunden)
                    end;
                let vClean := if i._HF_ReinigungsDauerStunden = null then
                        0
                    else
                        number(i._HF_ReinigungsDauerStunden)
                    end;
                let vProd := if i._HF_KonfDauerStunden = null then
                        0
                    else
                        number(i._HF_KonfDauerStunden)
                    end;
                let myOut := if i._HF_OutputProMinute = null then
                        0
                    else
                        number(i._HF_OutputProMinute)
                    end;
                let vMenge := if i.BuchungsmengeBlending = null then
                        0
                    else
                        number(i.BuchungsmengeBlending)
                    end;
                let vSum := vSetup + vClean + vProd;
                let vBase := if vSum = 0 then 1 else vSum end;
                "// CSS FIX: Komma durch Punkt ersetzen für Safari (z.B. 5,5% -> 5.5%)";
                let wC := replace(format(vClean / vBase * 100, "0.0"), ",", ".");
                let wS := replace(format(vSetup / vBase * 100, "0.0"), ",", ".");
                let wP := replace(format(vProd / vBase * 100, "0.0"), ",", ".");
                let tIcon := "➡";
                let tClass := "color:#d97706";
                if myOut > vGlobalAvg * 1.02 then
                    tIcon := "⬆";
                    tClass := "color:#059669"
                else
                    if myOut < vGlobalAvg * 0.98 then
                        tIcon := "⬇";
                        tClass := "color:#dc2626"
                    end
                end;
                let myId := string(i);
                let tpl := "
            <button type='button' class='h-btn' onclick='ui.popupRecord(""ID_PH"")'>
                <div class='h-content'>
                    <div class='h-row'>
                        <span class='txt-head'>DATE_PH</span>
                        <span class='txt-head'>Charge: CH_PH</span>
                    </div>
                    <div class='h-row'>
                        <span class='txt-sub'>MENGE_PH Stk</span>
                        <span class='txt-sub' style='color:#111;'>SUM_PHh</span>
                    </div>
                    <div class='h-row'>
                        <span class='txt-sub'>Output: <b style='STYLE_PH'>OUT_PH ICON_PH</b></span>
                        <span></span>
                    </div>
                    <div class='bar-bg'>
                        <div class='bar-seg' style='background-color:#3b82f6; width:WC_PH%;'>&nbsp;</div>
                        <div class='bar-seg' style='background-color:#f59e0b; width:WS_PH%;'>&nbsp;</div>
                        <div class='bar-seg' style='background-color:#10b981; width:WP_PH%;'>&nbsp;</div>
                    </div>
                </div>
            </button>";
                let s1 := replace(tpl, "ID_PH", myId);
                let s2 := replace(s1, "DATE_PH", format(i._HF_StoppDatumGesamt, "DD.MM.YY"));
                let s3 := replace(s2, "CH_PH", i.Chargennummer);
                let s4 := replace(s3, "STYLE_PH", tClass);
                let s5 := replace(s4, "OUT_PH", format(myOut, "#,##0.0"));
                let s6 := replace(s5, "ICON_PH", tIcon);
                let s7 := replace(s6, "SUM_PH", format(vSum, "#,##0.0"));
                let s8 := replace(s7, "WC_PH", wC);
                let s9 := replace(s8, "WS_PH", wS);
                let s10 := replace(s9, "WP_PH", wP);
                replace(s10, "MENGE_PH", format(vMenge, "#,##0"))
            end;
        html(css + "<div class='h-main'>" + "<div class='h-header'>" + "<span>Historie (" +
        vCount +
        ")</span>" +
        "<span>Ø " +
        format(vGlobalAvg, "0.0") +
        "/min</span>" +
        "</div>" +
        join(htmlCards, "") +
        "</div>")
    end
    

Content aside

  • vor 11 StundenZuletzt aktiv
  • 5Antworten
  • 51Ansichten
  • 3 Folge bereits