[JavaScript] Date: Datum und Zeit

// https://www.w3schools.com/jsref/jsref_obj_date.asp
// https://javascript.info/date

// akt. Datum + Uhrzeit
let dt_curr = new Date();
console.log(dt_curr.toString());

// Datum: 31.12.2018, Uhrzeit: 12:10:20,0
// Monat startet mit Index 0!
let d = new Date(2018, 11, 31, 12, 10, 20, 0);

// Mon Dec 31 2018 12:10:20 GMT+0100
console.log(d.toString());
// Mon, 31 Dec 2018 11:10:20 GMT
console.log(d.toUTCString());
// 2018-12-31T11:10:20.000Z
console.log(d.toISOString());
// 31.12.2018, 12:10:20
console.log(d.toLocaleString('de-DE'));
// 31.12.2018
console.log(d.toLocaleDateString('de-DE'));
// 12:10:20
console.log(d.toLocaleTimeString('de-DE'));

// Anzahl Millisekunden, seit 01.01.1970 00:00:00 UTC
console.log(Date.now());

[ABAP] SAP Gateway File-Download über DEFINE und GET_STREAM

SE80: DDIC-Typ anlegen “ZFILESTREAM”

Feldname    Name im Gateway   ABAP-Typ     Bemerkung
------------------------------------------------------------------------------------------------------------------
FILEKEY     FileKey           beliebig     eindeutige Referenz (Key) zur späteren Ermittelung der Datei im Backend
MIME_TYPE   MimeType          CHAR100      Platzhalter für MimeType der Datei
VALUE       Value             XSTRINGVAL   Platzhalter für Binärdaten

SEGW: neuer Entitätstyp zum Lesen der Datei

  • Name: “FileStream”, DDIC-Typ “ZFILESTREAM” importieren
Name      Schlüssel   EDM-Coretyp   Bezeichner        ABAP-Feldname
-------------------------------------------------------------------
FileKey   ja          Edm.String    FileId            FILEKEY
MimeType  nein        Edm.String    Mimetyp           MIME_TYPE
Value     nein        Edm.Binary    Media Ressource   VALUE
  • Haken bei Medium setzen

SE80: ZCL_…_MPC_EXT~DEFINE redefinieren

METHOD define.
  DATA: lo_entity   TYPE REF TO /iwbep/if_mgw_odata_entity_typ.
  DATA: lo_property TYPE REF TO /iwbep/if_mgw_odata_property.

* Aufruf Basisklasse
  super->define( ).

* Entität "FileStream" holen
  lo_entity = model->get_entity_type( iv_entity_name = zcl_..._mpc=>gc_filestream ).

  IF lo_entity IS BOUND.

* Feld für MimeType (==MIME_TYPE) als ContentType setzen
    lo_property = lo_entity->get_property( iv_property_name = 'MimeType' ).
    lo_property->set_as_content_type( ).

  ENDIF.
ENDMETHOD.

SE80: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM redefinieren

METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.
  DATA: lv_file        TYPE zcl_..._mpc=>ts_filestream.
  DATA: lv_stream      TYPE ty_s_media_resource.

* Welche Entität?
  CASE io_tech_request_context->get_entity_type_name( ).
    WHEN zcl_..._mpc=>gc_filestream.
* Schlüssel ("FILEKEY") ermitteln
      io_tech_request_context->get_converted_keys( IMPORTING es_key_values = lv_file ).

* gewünschte Binärdaten anhand des Schlüssels aus SAP lesen
      DATA: it_bin_data TYPE STANDARD TABLE OF raw255.
      
      it_bin_data = ...

* Dateinamen ermitteln        
      DATA: lv_filename TYPE skwf_filnm.
      
      lv_filename = ...

* Für die Umwandlung die Dateigröße der Binärdaten berechnen
      DATA(lv_size) = lines( it_bin_data ).
      DATA: lv_line LIKE LINE OF it_bin_data.
      DATA(lv_length) = 0.
* für Unicode-Kompatibilität IN BYTE MODE
      DESCRIBE FIELD lv_line LENGTH lv_length IN BYTE MODE.
      lv_size = lv_size * lv_length.

* Binärdaten in xstring für die Rückgabe konvertieren        
      CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
        EXPORTING
          input_length = lv_size
        IMPORTING
          buffer       = lv_stream-value
        TABLES
          binary_tab   = it_bin_data
        EXCEPTIONS
          failed       = 1
          OTHERS       = 2.

      IF sy-subrc = 0.        
* MIME-Typen der Datei ermitteln und an das Frontend übergeben
        DATA: lv_mimetype TYPE skwf_mime.
              
* aus Dateinamen den MIME-Typen ermitteln
        CALL FUNCTION 'SKWF_MIMETYPE_OF_FILE_GET'
          EXPORTING
            filename = lv_filename
          IMPORTING
            mimetype = lv_mimetype.
                
        lv_stream-mime_type = lv_mimetype.

* HTTP-Header-Infos setzen (Dateiname usw.)
        DATA(lv_lheader) = VALUE ihttpnvp( name  = 'Content-Disposition'
                                           value = |inline; filename="{ escape( val = lv_filename format = cl_abap_format=>e_url ) }";| ). " Datei im Tab inline (Plugin) öffnen
*                                           value = |outline; filename="{ escape( val = lv_filename format = cl_abap_format=>e_url ) }";| ). " Datei zum direkten Herunterladen / Öffnen anbieten

        set_header( is_header = lv_lheader ).

* alle Daten zum Frontend schicken
        me->copy_data_to_ref( EXPORTING is_data = lv_stream
                              CHANGING cr_data  = er_stream ).
      ENDIF.

    WHEN OTHERS.
* andere Entitäten standardmäßig behandeln
      super->/iwbep/if_mgw_appl_srv_runtime~get_stream(
        EXPORTING
          iv_entity_name          = iv_entity_name
          iv_entity_set_name      = iv_entity_set_name
          iv_source_name          = iv_source_name
          it_key_tab              = it_key_tab
          it_navigation_path      = it_navigation_path
          io_tech_request_context = io_tech_request_context
          IMPORTING
            er_stream             = er_stream
            es_response_context   = es_response_context ).
  ENDCASE.
ENDMETHOD.

Weiterführende Infos: SAP Fiori tricks: Get rid of $value in PDF display/downloads

[ABAP] OpenSQL: Subselect / Subqueries verwenden

* Subqueries können nicht für Pool- oder Clustertabellen verwendet werden
* ORDER BY kann nicht in einer Subquery verwendet werden
* bei der Verwendung von Subqueries wird das SAP buffering umgangen

* Beispiel 1 (Städte)
SELECT city,
       latitude,
       longitude
INTO TABLE @DATA(it_cities)
FROM sgeocity
WHERE city IN ( SELECT cityfrom FROM spfli WHERE carrid = 'LH' ).

cl_demo_output=>display( it_cities ).

* Beispiel 2 (Buchungen)
SELECT c~id,
       c~name,
       c~city,
       b~cancelled
  INTO TABLE @DATA(it_cust)
  UP TO 100 ROWS
  FROM sbook as b
  INNER JOIN scustom as c ON c~id = b~customid
  WHERE customid NOT IN ( SELECT customid FROM sbook WHERE cancelled EQ @abap_true ).

cl_demo_output=>display( it_cust ).

[JavaScript] Gleichheit

Strikte Gleichheit (‘===’)

  • prüft zwei Werte auf Gleichheit
  • ohne Konvertierung
let num = 0;
let obj = new String('0');
let str = '0';
let b = false;

// false
console.log(b === obj);
// false
console.log(num === b); 
// false
console.log(num === str);
// false
console.log(str === 1);
// false
console.log(obj === 1);
// true
console.log(num === 0);
// false
console.log(num === 1);

Lose Gleichheit (‘==’)

  • vergleicht zwei Werte auf Gleichheit
  • mit vorheriger Konvertierung zum gleichen Typ
let num = 0;
let obj = new String('0');
let str = '0';
let b = false;

// true
console.log(b == obj);
// true
console.log(num == b);
// true
console.log(num == str);
// false
console.log(str == 1);
// false
console.log(obj == 1);
// false
console.log(num == 1);
// true
console.log(num == 0);

Weiterführende Infos: Link

[JavaScript] JSON-Datei per HTTP-Request holen und parsen

// Link zur JSON-Datei
let sURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
// Request-Object
let request = new XMLHttpRequest();
// MIME-Typen
// txt: "text/plain"
// html: "text/html"
// json: "application/json"
request.overrideMimeType('application/json');
// Requestmethode
request.open('GET', sURL, true);
// Datentyp
request.responseType = 'text';
// Handler für asyncrone Antwort des Requests
// wenn Daten erfolgreich geladen
request.onload = function() {
  console.log('onload()');
  // gesamte Response ausgeben
  let sJSON = request.response;
  console.log(sJSON);
  
  // JSON-Daten parsen
  let oJSON = JSON.parse(sJSON);
  // Wert eines Attributes ausgeben
  console.log(oJSON.homeTown);
};
// bei Änderung des Ready-States
request.onreadystatechange = function () {
  console.log('onreadystatechange()');
  console.log(request.readyState);
  console.log(request.status);
  console.log(request.statusText);
};
// Request absenden
request.send();

[JavaScript] Eine Klasse definieren

Klassendefinition ab ES6

// https://javascript.info/class
// https://javascript.info/property-accessors
class Rechteck
{
  // Konstruktor
  constructor(h, b) {
    this.h = h;
    this.b = b;
  }
   
  // public Properties
  get flaeche() {
    return this.Flaeche();
  }
 
  set hoehe(value) {
    this.h = value;
  }
  
  set breite(value) {
    this.b = value;
  }
  
  // public Methoden
  Flaeche() {
    return this.h * this.b;
  }
  
  // statische Methoden
  static Calc(h, b) {
    return h * b;
  }
}
 
const q = new Rechteck(10, 10);
 
console.log(q.flaeche);
q.hoehe = 5;
console.log(q.Flaeche());
console.log(Rechteck.Calc(2, 3));
console.log(Object.getOwnPropertyNames(Rechteck.prototype));

herkömmlich über “function”

function Rechteck(h, b)
{ 
    this.h = h;
    this.b = b;
   
    Rechteck.prototype.Flaeche = function() {
      return this.h * this.b;
    }
}
 
let q = new Rechteck(10, 10);
 
console.log(q.Flaeche());
console.log(Object.getOwnPropertyNames(Rechteck.prototype));