#1 2015-06-29 20:58:52

fabioquestor
Member
From: Chapecó, SC, Brasil
Registered: 2014-05-19
Posts: 13
Website

TMVCApplication function : TMVCAction with param array

how can I make a function that I can spend an array parameter as it comes with named parameter. but I have dynamic parameters. each time I call the function with a different number of parameters, do not even know how to do on Delphi or in html.

example:

not

    function Login(const LogonName,PlainPassword: RawUTF8): TMVCAction;

yes

    function Login(const params: array of RawUTF8): TMVCAction;

not

    function CadastroSalvar(const p1, p2, p3, p4: RawUTF8): TMVCAction;

yes

    function CadastroSalvar(const p: TObjectList): TMVCAction;

Thanks

Offline

#2 2015-06-29 21:24:25

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: TMVCApplication function : TMVCAction with param array

Use a TRawUtf8DynArray or a variant containing a TDocVariant.

Offline

#3 2015-06-30 01:21:49

fabioquestor
Member
From: Chapecó, SC, Brasil
Registered: 2014-05-19
Posts: 13
Website

Re: TMVCApplication function : TMVCAction with param array

don't

only first param:

function TnWebMVCMenu.CadastroSalvar3(const p: variant): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p])
end;

{"ClassName":"EMVCException","Address":"0B91DB80","Message":"TMVCRendererFromViews.CommandRunMethod: InWebMVCMenu.CadastroSalvar2() execution error","context":"TMVCRendererFromViews.ExecuteCommand"}

function TnWebMVCMenu.CadastroSalvar2(const p: TRawUtf8DynArray): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p[0]])
end;

General
Remote Address:[::1]:8080
Request URL:http://localhost:8080/npmnGem/CadastroSalvar2
Request Method:POST
Status Code:500 Internal Server Error
Response Headers
view source
Accept-Encoding:synlz,gzip
Access-Control-Allow-Origin:
Content-Encoding:gzip
Content-Length:1372
Content-Type:text/html; charset=UTF-8
Date:Tue, 30 Jun 2015 01:15:45 GMT
Server:mORMot/1.18.1563 (Windows) Microsoft-HTTPAPI/2.0
Server-InternalState:0
X-Powered-By:Synopse mORMot 1.18.1563 http://synopse.info
Request Headers
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:20
Content-Type:application/x-www-form-urlencoded
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/npmnGem/Cadastro?Scope={%22Class%22:%22TnGemDMUsuarioGrupoUsu%22}
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36
Form Data
view source
view URL encoded
p:1
p:teste 1
p:10.5

Offline

#4 2015-06-30 04:53:24

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: TMVCApplication function : TMVCAction with param array

Put a json array as value, of course!

Offline

#5 2015-06-30 17:49:44

fabioquestor
Member
From: Chapecó, SC, Brasil
Registered: 2014-05-19
Posts: 13
Website

Re: TMVCApplication function : TMVCAction with param array

But like putting a json array as value?

		<form class="form-horizontal" action="CadastroSalvar2" method="post">
		  <div class="form-group">
			<label for="input1" class="col-sm-2 control-label">ID</label>
			<div class="col-sm-3">
			  <input type="number" class="form-control" id="input1" name="p[1]" placeholder="ID" value="1">
			</div>
			<div class="col-sm-1">
			  <input class="btn btn-default" type="button" value="...">
			</div>
			<div class="col-sm-6">
			  <input type="number" class="form-control" id="input1" placeholder="ID" value="1">
			</div>
		  </div>
				  <div class="form-group">
			<label for="input2" class="col-sm-2 control-label">Descricao</label>
			<div class="col-sm-3">
			  <input type="text" class="form-control" id="input2" name="p[2]" placeholder="Descricao" value="teste 1">
			</div>
			<div class="col-sm-1">
			  <input class="btn btn-default" type="button" value="...">
			</div>
			<div class="col-sm-6">
			  <input type="text" class="form-control" id="input2" placeholder="Descricao" value="teste 1">
			</div>
		  </div>
				  <div class="form-group">
			<label for="input3" class="col-sm-2 control-label">Preco</label>
			<div class="col-sm-3">
			  <input type="number" class="form-control" id="input3" name="p[3]" placeholder="Preco" value="10.5">
			</div>
			<div class="col-sm-1">
			  <input class="btn btn-default" type="button" value="...">
			</div>
			<div class="col-sm-6">
			  <input type="number" class="form-control" id="input3" placeholder="Preco" value="10.5">
			</div>
		  </div>
		  
		  <div class="form-group">
			<div class="col-sm-offset-2 col-sm-10">
			  <button type="submit" class="btn btn-default">Salvar</button>
			</div>
		  </div>
		</form>	  

For

function TnWebMVCMenu.CadastroSalvar2(const p: TRawUtf8DynArray): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p[0],
     'pp2',p[0]])
end;

But don´t go


I tried so well.

...
name="p.a1" 
...
name="p.a2" 
...
name="p.a3" 
...

For

function TnWebMVCMenu.CadastroSalvar3(const p: variant): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p.a1,
     'pp2',p.a2])
end;

Neither.

Request Payload
p={"a1":1,"a2":"dfasdfa"}

Thus it works for CadastroSalvar3, but I do not know how to do post the form to do so.

Offline

#6 2015-06-30 17:57:46

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: TMVCApplication function : TMVCAction with param array

I suppose you may use a JavaScript function?

The onclick event of the button would let JavaScript compute the JSON, then send it at URI, or as POST body to the server.

I did not test it yet, but it should work.

Offline

#7 2015-06-30 19:28:22

fabioquestor
Member
From: Chapecó, SC, Brasil
Registered: 2014-05-19
Posts: 13
Website

Re: TMVCApplication function : TMVCAction with param array

source original

function TSQLRestServerURIContext.GetInputAsTDocVariant: variant;
var i: integer;
    v: variant;
    MultiPart: TMultiPartDynArray;
begin
  VarClear(result);
  FillInput;
  if fInput<>nil then begin
    with TDocVariantData(result) do begin
      InitFast;
      for i := 0 to (length(fInput) shr 1)-1 do begin
        GetVariantFromJSON(pointer(fInput[i*2+1]),false,v,@JSON_OPTIONS[true]);
        AddValue(fInput[i*2],v);
      end;
    end;
  end else
  if InputAsMultiPart(MultiPart) then
    with TDocVariantData(result) do begin
      InitFast;
      for i := 0 to high(MultiPart) do
        with MultiPart[i] do
          if ContentType=TEXT_CONTENT_TYPE then begin
            RawUTF8ToVariant(Content,v);
            AddValue(Name,v); // append as regular "Name":"TextValue" field
          end else // append binary file as an object, with Base64-encoded data
            AddValue(Name,_ObjFast(['data',BinToBase64(Content),
              'filename',FileName,'contenttype',ContentType]));
    end;
end;

changer source

function TSQLRestServerURIContext.GetInputAsTDocVariant: variant;
var i,
    APos: integer;
    v,
    vresult: variant;
    MultiPart: TMultiPartDynArray;
    AObjectName,
    AParName: RawUTF8;
    AFoundObject: Boolean;
begin
  AObjectName := '';
  VarClear(vresult);
  FillInput;
  if fInput<>nil then begin

    AFoundObject := False;
    APos := pos('.', fInput[0]);
    if (APos > 0) then begin
      AObjectName := Copy(fInput[0], 1, APos - 1);
      for i := 0 to (length(fInput) shr 1)-1 do begin
        AParName := fInput[i*2];
        APos := pos('.', AParName);
        if (APos > 0) and (AObjectName = Copy(AParName, 1, APos - 1)) then begin
          AFoundObject := True;
        end else begin
          AFoundObject := False;
          continue;
        end;
      end;
    end;

    with TDocVariantData(vresult) do begin
      InitFast;
      for i := 0 to (length(fInput) shr 1)-1 do begin
        GetVariantFromJSON(pointer(fInput[i*2+1]),false,v,@JSON_OPTIONS[true]);
        AParName := fInput[i*2];

        if AFoundObject then
          AParName := Copy(AParName, APos + 1, MaxInt);

        AddValue(AParName,v);
      end;
    end;
  end else
  if InputAsMultiPart(MultiPart) then
    with TDocVariantData(vresult) do begin
      InitFast;
      for i := 0 to high(MultiPart) do
        with MultiPart[i] do
          if ContentType=TEXT_CONTENT_TYPE then begin
            RawUTF8ToVariant(Content,v);
            AddValue(Name,v); // append as regular "Name":"TextValue" field
          end else // append binary file as an object, with Base64-encoded data
            AddValue(Name,_ObjFast(['data',BinToBase64(Content),
              'filename',FileName,'contenttype',ContentType]));
    end;
  if AFoundObject then begin
    VarClear(result);
    with TDocVariantData(result) do begin
      InitFast;
      AddValue(AObjectName,vresult);
    end;
  end else
    result := vresult;
end;

input

p.a1=5&p.a2=dfasdfa

before change

{"p.a1":5,"p.a2":"dfasdfa"}

after change

{"p":{"a1":5,"a2":"dfasdfa"}}

sorry the few sources thought, but I'm in a hurry.

it can be better and integer, or change to a different concept, provided it is nome.property


this works with this sources

function TnWebMVCMenu.CadastroSalvar3(const p: variant): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p.a1,
     'pp2',p.a2])
end;

Offline

#8 2015-06-30 21:50:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,183
Website

Re: TMVCApplication function : TMVCAction with param array

I've implement this feature, which sound in fact handy.
See http://synopse.info/fossil/info/c6dad25635
It follows another pattern, dedicated to MVC (I did not want to change the default TSQLRestServerURIContext behavior).

The associated updated documentation:

Variable input parameters

If you want to support a variable number of named parameters, you can define a variant input parameter, and provide the input as a JSON document, using a TDocVariant storage. But marshalling the context as JSON would involve using some JavaScript in the HTML page, which may not be very convenient.

If you want to handle a non-fixed set of regular URI or POST value, you can prefix all the incoming parameter names with the dotted name of a single defined variant.
For instance, if you have the following controller method:

function TnWebMVCMenu.CadastroSalvar3(const p: variant): TMVCAction;

Then you can supply as parameter at URI level:

p.a1=5&p.a2=dfasdfa

And you would be able to handle them in the controller body:

function TnWebMVCMenu.CadastroSalvar3(const p: variant): TMVCAction;
begin
  GotoView(result,'Cadastro',
    ['pp1',p.a1,
     'pp2',p.a2])
end;

You are now free to specify some versatile HTML forms in your views, and provide the controller with any kind of input parameters.
Of course, it may sound safer and easier to explicitly define and name each one of the input parameters, with simple types like integer or RawUTF8. But this convention may help you work with any kind of HTML views.



Thanks for the feedback!

Offline

#9 2015-07-02 12:27:13

fabioquestor
Member
From: Chapecó, SC, Brasil
Registered: 2014-05-19
Posts: 13
Website

Re: TMVCApplication function : TMVCAction with param array

Thank you, it was show.

Offline

Board footer

Powered by FluxBB