Kundendatei im WEB

Vom Front-End bis SOAP.

Moderator: Moderatoren

Antworten
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Kundendatei im WEB

Beitrag von azzo »

Hallo Freunde,
hat jemand von euch schon eine Kundendatei im Web.

Ich verwende "bootstrap tables".
Ich lese zum Testen 500 Datensätze aus der Datenbank und zeige diese an.

Bei mehr Datensätze, gibt es dann schon Wartezeiten, bis die Tabelle gefüllt ist.
Wie macht man das aber jetzt am besten, mit dem Paging, der Suche und dem Sortieren der Spaten.
Standardmäßig sind dann nur die 500 Datensätze, die gerade im Zugriff sind, adressiert.
Ich bin es von Desktop gewohnt, dass ich in den Spalten inkrementelle Suche über die ganze Datei habe.

Wie bildet man das im Web nach?

Mit freundlichem Gruß
Otto
Benutzeravatar
nightcrawler
1000 working lines a day
1000 working lines a day
Beiträge: 650
Registriert: Di, 24. Apr 2012 16:33
Wohnort: 72184 Weitingen
Hat sich bedankt: 3 Mal
Danksagung erhalten: 96 Mal
Kontaktdaten:

Re: Kundendatei im WEB

Beitrag von nightcrawler »

Ich weiss jetzt nicht, inwieweit dies mit Bootstrap geht, aber mit odata hättest Du eine gute Möglichkeit. Die Daten werden über eine URI geholt, dort wird dann mitgegeben, nach was sortiert wird und welche Datensätze zurückkommen sollen (https://www.odata.org).
Beispiel (Datensätze 40-60 nach Name sortiert):

Code: Alles auswählen

https://services.odata.org/OData/OData.svc/Category(1)/Products?$skip=40&$top=20&$orderby=name
--
Joachim
Joachim Dürr Softwareengineering
https://www.jd-engineering.de
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Kundendatei im WEB

Beitrag von Tom »

Es kommt darauf an, was die Latenz verursacht. Wenn es im Backend dauert, oder die Bandbreite für die Datenlieferung zu schmal ist, helfen eigentlich nur Paging und Nachladen. Ansonsten kann man große Tabellen mit ein paar Zeilen Javascript ziemlich cool eindampfen, das machen die Suchfunktionen ja auch so. Der style.display-Tag ist Dein Freund. Wenn er "none" enthält, werden z.B. Tabellenzeilen (tr) nicht angezeigt (tr.style.display = "none" blendet die Zeile aus). Wenn man z.B. Spalten mit Zeilennummern mitführt, kann man dann in einem eigentlich fertig geladenen Dokument blättern, ohne dass etwas nachgeladen werden muss, das ist ein Zehnzeiler in einem Javascript. Aber für all diese Zwecke gibt es da draußen tonnenweise Codesnippets.
Herzlich,
Tom
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo Freunde,

Vielen Dankfür eure Antworten.

Ich habe jetzt Versuche am Smartphone gemacht. Aber wenn du hier zB 30000 Datensätze in die Table lädst, dann steht das Programm. Hier hat man einfach eine Ladezeit.

Ich denke, da wird man um ein Nachladen mit AJAX nicht herumkommen.

Das werde ich wohl alles programmieren müssen.
Klick auf den Spaltenkopf und dann erneut zB 150 Datensätzen einlesen..
Und die Suche wird man auch auf den Server verlegen müssen.

LG

Otto
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo,
ich denke ich kann das mit

data-side-pagination="server"
von BS tables lösen.

Nochmals vielen dank.
Liebe Grüße
Otto

Code: Alles auswählen

queryParams

    Attribute: data-query-params
    Type: Function
    Detail:
    When requesting remote data, you can send additional parameters by modifying queryParams.
    If queryParamsType = 'limit', the params object contains: limit, offset, search, sort, order.
    Else, it contains: pageSize, pageNumber, searchText, sortName, sortOrder.
    Return false to stop request.
    Default: function(params) { return params }
    Example: Query Params
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Re: Kundendatei im WEB

Beitrag von Lewi »

@Otto:

"Pagination" ist ein Abend füllendes Thema!

Die einfachste Möglichkeit ist, dass Du mit einem Request alle gewünschten Datensätze in den Brower lädts und die Pagination mittels JS selbst programmierst. Das bedeutet, dass entweder die Buttons für die einzelnen Seiten mit JS erzeugt werden oder nur <Vor> <zurück> anbietest.
Die Anzeige der Daten pro Seite erfolgt dann über die Manipulation des DOM.
Bevor Du Dich für diesen Weg entscheidest, solltest Du prüfen, wie lange es dautet, nur die Datensätze im Frontend zur Verfügung zu stellen, ohne dass irgendwelche Daten angezeigt werden. Wenn die Page bei einigen Hundert Datensätzen erst nach einigen Sekunden angezeigt wird, kann Du diesen Weg "vergessen".

Bei der Pagination musst Du entscheiden, ob die einzelnen Seiten per Request abgerufen werden sollen oder über eine API. Bei einem Request wird die Seite im Backend komplett neu erzeugt, über API werden Daten an das Frontend geliefert und im Weiteren mittels JS verarbeitet.
Sowohl bei einem Request wie auch über API müssen die Werte für ein „Offset“ und ein „Limit“ für die SQL-Datenselektion an das Backend bzw. API geliefert werden, um die entsprechenden Datensätze zu liefern.
How ever …. Wenn Du Dich für einen Weg entschieden hast, dann wird Dir hier sicherlich weiter geholfen.

Aktuell entwickel ich gerade für eine Webpage ein Infinity-Scroll. Allerdings nutze ich dazu den Tech-Stack: Vue 3, JS und TailWind CSS. Für mich ist Infnity-Scolling die eleganteste Methode, aber auch entwicklungseitig Neuland.

Grüße,
Olaf
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Kundendatei im WEB

Beitrag von Tom »

Hallo, Lewi.
Die einfachste Möglichkeit ist, dass Du mit einem Request alle gewünschten Datensätze in den Brower lädts und die Pagination mittels JS selbst programmierst. Das bedeutet, dass entweder die Buttons für die einzelnen Seiten mit JS erzeugt werden oder nur <Vor> <zurück> anbietest.
Die Anzeige der Daten pro Seite erfolgt dann über die Manipulation des DOM.
Genau das hatte ich zuvor erläutert.

Aber wenn das Backend zu lange braucht, um die Daten aufzubereiten, ist das nicht der richtige Weg. Auch das hatten wir schon.
Herzlich,
Tom
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo Olaf, hallo Tom,

vielen Dank. Ich bin sehr "basic" unterwegs.
Ich habe mir nun diese data.prg zum Antworten auf die Serveranfrgen gemacht.

Ich werde in die Webseite nun noch eine Combobox einbauen, wo man die Suche eingrenzen kann.

Eine andere Frage.
Hat es auf das Programm einen Einfluss, wenn man Variable definiert und diese abarbeitet oder einfach die Felder auswertet?
Hier ein Beispiel:

cValType := VALTYPE( ( cAlias )->( FieldGet( m ) ) )
cFeldName := ( cAlias )->( FieldName( m ) )
uWert := ( cAlias )->( FieldGet( m ) )

*****************************
auswerten der Variable vs.
if cValType = "N"

oder Feld direkt

if VALTYPE( ( cAlias )->( FieldGet( m ) ) ) = "N"

*****************************

while n < nLimit .and. ( cAlias )->( ! Eof() )
n++
AAdd( aRows, { 'keyno' => ( cAlias )->( OrdKeyNo() ),;
'_recno' => ( cAlias )->( Recno() ) } )

cValType := VALTYPE( ( cAlias )->( FieldGet( m ) ) )
cFeldName := ( cAlias )->( FieldName( m ) )
uWert := ( cAlias )->( FieldGet( m ) )

for m = 1 to ( cAlias )->( FCount() )

if cValType = "N"
hb_HSet( ATail( aRows ), cFeldName, STR( uWert ) )

elseif cValType = "D"
cDate := DTOS( uWert )
cDate := substr( cDate,1,4) + "-" + substr( cDate,5,2)+ "-" + substr( cDate,7,2)
hb_HSet( ATail( aRows ), cFeldName, cDate )

elseif cValType= "L"
if ( cAlias )->( FieldGet( m ) ) = .t.
hb_HSet( ATail( aRows ), cFeldName, "true" )
else
hb_HSet( ATail( aRows ), cFeldName, "false" )
endif

else
hb_HSet( ATail( aRows ),cFeldName, uWert )
if LEN( ALLTRIM( ( cAlias )->( FieldGet( m ) ) ) ) = 0
hb_HSet( ATail( aRows ), cFeldName, " " )
else
hb_HSet( ATail( aRows ), cFeldName, convertUmlaute( uWert ) )
endif
endif
next

( cAlias )->( DbSkip() )
end


( cAlias )->( DbSkip() )
end


while n < nLimit .and. ( cAlias )->( ! Eof() )
n++
AAdd( aRows, { 'keyno' => ( cAlias )->( OrdKeyNo() ),;
'_recno' => ( cAlias )->( Recno() ) } )
for m = 1 to ( cAlias )->( FCount() )

if VALTYPE( ( cAlias )->( FieldGet( m ) ) ) = "N"
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), STR( ( cAlias )->( FieldGet( m ) ) ) )

elseif VALTYPE( ( cAlias )->( FieldGet( m ) ) )= "D"
cDate := DTOS( ( cAlias )->( FieldGet( m ) ) )
cDate := substr( cDate,1,4) + "-" + substr( cDate,5,2)+ "-" + substr( cDate,7,2)
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), cDate )

elseif VALTYPE( ( cAlias )->( FieldGet( m ) ) ) = "L"
if ( cAlias )->( FieldGet( m ) ) = .t.
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), "true" )
else
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), "false" )
endif

else
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), ( cAlias )->( FieldGet( m ) ) )
if LEN( ALLTRIM( ( cAlias )->( FieldGet( m ) ) ) ) = 0
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), " " )
else
hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), convertUmlaute( ( cAlias )->( FieldGet( m ) ) ) )
endif
endif
next

( cAlias )->( DbSkip() )
end
Mit freundlichem Gruß
Otto


Meine data.prg

Code: Alles auswählen


// Table Options
// https://bootstrap-table.com › docs › api › table-options
//  data-side-pagination="server"
//  data-query-params="queryParams"
//  queryParams

    //  Attribute: data-query-params
    //  Type: Function
    //  Detail:
    //  When requesting remote data, you can send additional parameters by modifying queryParams.
    //  If queryParamsType = 'limit', the params object contains: limit, offset, search, sort, order.
    //  Else, it contains: pageSize, pageNumber, searchText, sortName, sortOrder.
    //  Return false to stop request.
    //  Default: function(params) { return params }
    //  Example: Query Params


REQUEST DBFCDX
REQUEST DBFFPT


function Main()
	local dat 			:= {=>}
	local aRows 		:= {}
	local hParam		:= AP_GetPairs()
	local cDbf			:= PATH_DATA + hParam[ 'tabla' ] + '.dbf'	
	local cCdx			:= PATH_DATA + hParam[ 'tabla' ] + '.cdx'	
	local cSearch 		:= hParam[ 'search' ] 
	local nOffset 		:= val( hParam[ 'offset' ] )
	local nLimit 		:= val( hParam[ 'limit' ] )
	local n 		   	:= 0, m
	local nTotal 
	local cDate 		:= ""

	nOffset := IF( nOffset == 0, 1, nOffset )	
	USE ( cDbf ) SHARED NEW VIA 'DBFCDX'
	if File( cCdx )
	   SET INDEX TO ( cCdx )
	else
		if ! Empty( cSearch )
			SET FILTER TO cSearch
		endif		
	endif

	cAlias = Alias()
	( cAlias )->( DbGoTop() )
	if ! Empty( cSearch )
	   ( cAlias )->( OrdScope( 0, cSearch ) )
	   ( cAlias )->( OrdScope( 1, cSearch  ) )
	endif	
		
	if ! Empty( nOffset )
	   ( cAlias )->( OrdKeyGoto( nOffset ) )
	endif	

	while n < nLimit .and. ( cAlias )->( ! Eof() ) 
		n++	
		AAdd( aRows, { 'keyno'  => ( cAlias )->( OrdKeyNo() ),;
							'_recno' => ( cAlias )->( Recno() ) } )
	   for m = 1 to ( cAlias )->( FCount() )

			if VALTYPE( ( cAlias )->( FieldGet( m ) ) ) = "N"
				hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), STR( ( cAlias )->( FieldGet( m ) ) ) )

		 	elseif VALTYPE( ( cAlias )->( FieldGet( m ) ) )= "D"
				cDate := DTOS( ( cAlias )->( FieldGet( m ) ) )
				cDate := substr( cDate,1,4) + "-" +  substr( cDate,5,2)+ "-" +  substr( cDate,7,2)
				hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), cDate	)
	
			elseif VALTYPE( ( cAlias )->( FieldGet( m ) ) ) = "L"
				if ( cAlias )->( FieldGet( m ) ) = .t.
				hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), "true"	)
				else
				hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ),  "false"	)
				endif
		 
			else
				hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), ( cAlias )->( FieldGet( m ) ) )
				if LEN( ALLTRIM(  ( cAlias )->( FieldGet( m ) )  ) ) = 0
					hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ),  " "	)
				 else
					hb_HSet( ATail( aRows ), ( cAlias )->( FieldName( m ) ), convertUmlaute( ( cAlias )->( FieldGet( m ) ) ) )
				 endif
		 	endif
		next	

		( cAlias )->( DbSkip() )			
	end			
	
	COUNT TO nTotal

	dat[ 'total' ] 				:= (cAlias)->( ordKeyCount() )	
	dat[ 'totalNotFiltered' ] 	:= nTotal
	dat[ 'rows' ] 				   := aRows

	AP_SetContentType( "application/json" )
	
	?? hb_jsonEncode( dat ) 

return nil
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: Kundendatei im WEB

Beitrag von Martin Altmann »

Moin Otto,
zu Deiner anderen Frage: Klar - Performance, sofern es häufiger passiert! Jeder Funktionsaufruf muss die Parameter zwischenspeichern und Zugriff auf den Stack realisieren. Wenn Du also immer wieder ValType() nutzt, dauert das länger, als das Ergebnis dieses ValType()-Aufrufes einer Variablen zuzuweisen und diese dann mit einem Stringvergleich auszuwerten.
In einem normalen Programm (mit GUI etc.) macht sich das nicht so bemerkbar. In anderen Konstellationen (z.B. verschachtelte Funktionsaufrufe oder häufigere Abfragen) kann dadurch aber schon eine gewisse Verlangsamung eintreten. Aber sicherlich (im Normalfall) eher im Bereich von Sekunden (bei entsprechend großem Umfang).

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo Martin,
vielen Dank.
Mit freundlichem Gruß
Otto
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo Freunde,
Eigentlich funktioniert der Browser im Web erstaunlich performant.
Ich habe mir das nicht erwartet.
Der Webserver läuft im Haus und hat eine 100/100 Anbindung ans Internet.
Ich greife auf DBF Dateien zu.
Mit freundlichem Gruß
Otto
Bild
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Hallo Freunde,
Ich habe mich für separate Webseiten zur Bearbeitung der Adressen entschieden.
Wenn ich eine Karte öffne, erstelle ich eine Navigationsschaltfläche. Sie können mehrere Karten gleichzeitig öffnen. Zwischen den Karten können Sie mit einem Klick auf die entsprechende Schaltfläche navigieren.

Die Schaltflächen sind mit dem Vor- und Nachnamen beschriftet. Wenn Sie dann eine Karte schließen, aktualisiert sich dieses Hauptfenster mit einem Timer und löscht die Navigationsschaltflächen, die nicht mehr gültig sind.

Mit freundlichem Gruiß
Otto

Bild

https://mybergland.com/fwforum/gasteditieren.mp4
Benutzeravatar
Lewi
1000 working lines a day
1000 working lines a day
Beiträge: 830
Registriert: Di, 07. Feb 2006 14:10
Wohnort: Hamburg
Danksagung erhalten: 2 Mal

Re: Kundendatei im WEB

Beitrag von Lewi »

Wenn ich es recht verstehe, muss erst ein Datensatz markiert werden um ihn anschließend editieren zu können?

Ich würde eine zusätzliche Spalte für ein Edit-Button einfügen, über den dann die Daten bearbeitet werden können. Es wäre auch sinnvoll, dass man mit einem Doppel-Klick die Datail-Ansicht wechselt. Dazu wäre nur etwas JS erforderlich.

Wenn ich den Code ansehe, graust es mir. Nein, nicht deshalb, weil Dein Code so schlecht ist, sondern allein aus dem Grund, welcher Coding-Aufwand nötig ist, um Daten vom Backend ins Frontend zu schaufeln. Mal abgesehen davon, dass der Code für die Erstellung der HTML-Seite noch dazu kommt.

XBase++ mag ja für C/S Architekturen und PC-Anwendungen eine solide Programmiersprache sein, aber für Web-Anwendungen? Nicht wirklich!
Für eine Kunden-Verwaltung mit den von Dir gezeigten Features brauche ich unter PHP in Verbindung mit einem Framework maximal einen halben Tag. Aber nicht deshalb, weil ich ein super schneller Entwickler bin, sondern weil im Backend der Code in 20 Minuten geschrieben ist, die restliche Zeit im wesentlichen für HTML, CSS, JS und Design darauf geht. Und das auch nur dann, wenn ich bei "Null" anfange.

Ich sehe die Zukunft von xBase++ eher düster. Ich habe vor, dies in Rahmen eines Artikel näher aufzuzeigen. To be continued ....
Benutzeravatar
azzo
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 483
Registriert: So, 28. Mär 2010 19:21
Danksagung erhalten: 11 Mal

Re: Kundendatei im WEB

Beitrag von azzo »

Login und Kundensuche

Bild

Bild
Antworten