Daml-ui-template React function and Action with 2 arguments

I am further experimenting and expanding on the UI-template example for Report.js.

How would I expand the following function to include 2 arguments instead of only “newOwner” ?
I tried, “comma”. “curly brackets”, etc…

const exerciseGive = function(cid, newOwner) {
ledger.exercise(Main.Asset.Give, cid, { newOwner });

Also applies to the action:

actions={[[“Give”, (c, newOwner) => { exerciseGive(c.contractId, newOwner); }, “New Owner”]]}

Secondly,
I want to assign the current User as a Party into the function and action. How do I assign my current user as an argument ?

2 Likes

The daml-ui-template currently just supports exercising choices with a single parameter (or none). But the components in there, specifically the Contracts component, are really just meant as examples for you to adapt, not to be used as is in the final application. So you can for example just copy the code from Contracts into your own component and adjust it to your needs. When taking in > 1 parameters you’d anyway probably don’t want to display these inline in a contracts table, but maybe would want to pop up a form dialogue.

As for your other question to get the currently logged in user party you can use const party = useParty().

1 Like

Thanks. useParty() worked

my question was very similar to

My Daml

template Network
with
operator : Party
where
signatory operator
controller operator can
nonconsuming InviteHealthClinic : ContractId HealthClinicInvitation
with
healthclinic : Party
do
create HealthClinicInvitation with healthclinic, operator
nonconsuming InviteCitizen : ContractId CitizenInvitation
with
citizen : Party
do
create CitizenInvitation with citizen, operator

template HealthClinicInvitation
with
operator : Party
healthclinic : Party
where
signatory operator
controller healthclinic can
AcceptInvitation : ContractId HealthClinicRole
do
create HealthClinicRole with healthclinic, operator

My react code: Report.js

export default function Report() {

const ledger = useLedger();
const assets = useStreamQuery (Main.Network);
const exerciseInviteHealthClinic = function(cid, operator, healthclinic ) {
ledger.exercise(Main.Network.InviteHealthClinic, cid, {operator: operator, healthclinic: healthclinic })};
const exerciseInviteCitizen = function(cid , citizen ) {
ledger.exercise(Main.Network.InviteCitizen, cid, citizen)};
const ops = useParty();
return (

<>
  <Contracts
    contracts={assets.contracts}
    columns={[
      ["ContractId", "contractId"],
      ["TemplateId", "templateId"],
      ["Operator", "payload.operator"]
    ]}

   actions={[

[“InviteHealthClinic”, (c, healthclinic ) => { exerciseInviteHealthClinic(c.contractId, {operator: ops, healthclinic: healthclinic}); }, “Healthclinic”],
]}
/>
</>
);
}

Is currently causing the following error

VM967:1 POST http://localhost:3000/v1/exercise 400 (Bad Request)
(anonymous) @ VM967:1
(anonymous) @ browser-ponyfill.js:516
fetch @ browser-ponyfill.js:453
(anonymous) @ index.js:178
step @ index.js:33
(anonymous) @ index.js:14
(anonymous) @ index.js:8
push…/node_modules/@daml/react/node_modules/@daml/ledger/index.js.__awaiter @ index.js:4
Ledger.submit @ index.js:174
(anonymous) @ index.js:350
step @ index.js:33
(anonymous) @ index.js:14
(anonymous) @ index.js:8
push…/node_modules/@daml/react/node_modules/@daml/ledger/index.js.__awaiter @ index.js:4
Ledger.exercise @ index.js:339
exerciseInviteHealthClinic @ Report.js:14

  1. {errors: Array(1), status: 400}

  2. errors: Array(1)

1. 0: ""JsonError: spray.json.DeserializationException: Can't read {

“operator”: {
“operator”: “Operator”,
“healthclinic”: “AtriumHealth”
}
} as DamlLfRecord c94a6ca42d2899213eb9634a997a173f12698d32c69781559e077163792aeddf:Main:InviteHealthClinic, missing field ‘healthclinic’"

2. length: 1
3. __proto__: Array(0)
  1. status: 400
  2. proto: Object

You are passing already the full argument into the operator parameter for your exerciseInviteHealthClinic function. You can either change the function to take a single args parameter that you then pass directly to the choice, or you change it to just take the healthclinic parameter, and use the ops party as the operator (which you’ll have to move up to before the function. For the latter the code would look like this:

export default function Report() {

  const ledger = useLedger();
  const assets = useStreamQuery (Main.Network);
  const operator = useParty();

  const exerciseInviteHealthClinic = function(cid, healthclinic ) {
    ledger.exercise(Main.Network.InviteHealthClinic, cid, { operator, healthclinic });
  };

  const exerciseInviteCitizen = function(cid , citizen ) {
    ledger.exercise(Main.Network.InviteCitizen, cid, citizen)
  };

  return (
    <>
      <Contracts
        contracts={assets.contracts}
        columns={[
          ["ContractId", "contractId"],
          ["TemplateId", "templateId"],
          ["Operator", "payload.operator"]
        ]}
      actions={[
        [“InviteHealthClinic”, (c, healthclinic ) => { exerciseInviteHealthClinic(c.contractId, healthclinic); }, “Healthclinic”],
      ]}
      />
    </>
  );
}

Side note: you can format code nicely by putting it into a pair of triple backticks: ```

That makes sense. I updated the code

Ran into the next issue unfortunately.

Uncaught (in promise) Error: Trying to look up template c94a6ca42d2899213eb9634a997a173f12698d32c69781559e077163792aeddf:Main:HealthClinicInvitation.
at Object.push…/node_modules/@daml/types/index.js.exports.lookupTemplate (index.js:30)
at index.js:72
at decoder.ts:795
at andThen (result.ts:130)
at Decoder.decode (decoder.ts:795)
at Decoder.decode (decoder.ts:312)
at Decoder.decode (decoder.ts:501)
at decodeValue_1 (decoder.ts:371)
at decoder.ts:375
at Array.reduce ()
at Decoder.decode (decoder.ts:373)
at Decoder.decode (decoder.ts:312)
at Decoder.run (decoder.ts:716)
at Ledger. (index.js:357)
at step (index.js:33)
at Object.next (index.js:14)
at fulfilled (index.js:5)

I also saw the following Warn issue show up in the JSON-API Console:

10:59:15.714 [http-json-ledger-api-akka.actor.default-dispatcher-6] WARN akka.actor.ActorSystemImpl - Illegal header: Illegal ‘origin’ header: Illegal origin: Invalid input ‘/’, expected DIGIT or ‘EOI’ (line 1, column 22): http://localhost:7575/

Looks like your JS generated code is out of sync with the compiled DAML models. Make sure to follow the steps here each time you modify your DAML models.

Followed the instructions but still encountered the issue

When I submit the create and choice option on the JSON-API the system seems to work as expected.

Also make sure to kill and restart your dev server (the one started with daml start)

Tried that already,

After some more digging. I found that the exercise choice contract is actually executing and a new record is added in the database in the Contracts Table.

Some other code is still creating the errors on the page

I have added a link to a video I uploaded on slack
https://damldriven.slack.com/files/UUGFPFVQB/F013DPQ5X6H/2020-05-11_17-12-04.mkv

Ok, that’s an odd issue, but I think I’ve seen this before. It could be that two versions of @daml/types are being loaded. Can you do the nuclear option:

rm -rf daml2js
daml build
daml codegen js -o daml2js daml/model/.daml/dist/*.dar
cd ui
rm -rf build
rm -rf node_modules
yarn install --force --frozen-lockfile
yarn start

And let me know if that resolves it? If not, PM me your email and I’ll jump on a call to help you resolve this.

Thanks. Will give it a try

Solved the problem. Thanks for the help

Great to hear!

Just to add to this thread: we’ve also observed when users upgrade from previous versions of the SDK, in particular v0.13.55, that the yarn.lock file in the UI directory can get messed up. So if the above doesn’t resolve the issue for you, try deleting the yarn.lock file in your UI directory and then perform the above steps (just with a normal yarn install without the additional parameters).

1 Like