cancel
Showing results for 
Search instead for 
Did you mean: 

Update single attribute of a record variable

It is currently possible, and quite useful, to create global of screen variables containing a record (or what us, old-timers, used to call a data structure):

 

UpdateContext({MyRecord:{Id:1, Description: “Some text”, “IsCompleted”:false}});

We can then refer to a specific attribute of this variable in functions:

 

Label.Color = If(MyRecord.IsCompleted, Black, Red)

However, it is not possible to update only one attribute of the variable without recreating the complete record, which is a pain when the record contains many attributes.  Possible solutions could be :

 

UpdateContext({MyRecord.IsCompleted : true})
Patch(,MyRecord,{IsCompleted : true}) //note that the first parameter of patch is omitted
UdpateRecord(MyRecord,{IsCompleted : true})  //New function
Status: Completed
Comments
CarlosFigueira
Power Apps

@leo41 that's not the case; if the record was created originally with Set (i.e., it's a global variable), then you need to use Set to update it: Set(globalVar: Patch(globalVar, { field: "New value" }))

If the record was created using UpdateContext (i.e., it's a screen/context variable), then you need to use UpdateContext to udate it: UpdateContext({ contextVar: Patch(contextVar, { field: "New value" }) })

fpctest
Regular Visitor

This is still a huge problem with PowerApps and really diminishes its usability and functionality. Please fix this. This idea is not completed! The patch function is the buggiest thing I had to work with in my life.

hexparker
Advocate I

Not sure if this helps anyone, but the actual syntax that I got to work just now was the following:

 

Set(myGlobalVariable, Patch(myGlobalVariable, {Field1: "value1", Field2: 0}))

This updates just the two attributes (Field1 and Field2) in my global variable, and leaves the rest alone.

AIUYM19
Advocate V

OK, I'll weigh in on this, too...

 

@CarlosFigueira, your Patch function as-written works only under a very specific set of circumstances. As a counterexample, if you create a record variable in the OnVisible property of a screen using something like this...

UpdateContext({
    NewRecord: {
        Field1: "Value1",
        Field2: "Value2"
    }
})

 ...then attempt to update one of the field values in the OnChange property of a dropdown or combobox control on that screen like this...

UpdateContext({
    NewRecord: Patch(
        NewRecord,
        {
            Field1: Self.Selected
        }
    )
})

...PowerApps will throw an error ("Invalid argument type. Expecting a table value instead," and "The first argument of Patch should be a collection"). PowerApps, for whatever reason, does not understand that you're trying to merge two records here; it's attempting to use NewRecord as a data source within which it will attempt to find a record matching the second argument.

 

The only way around this (that I can find) is @nathanpsmith's workaround of creating a temporary collection, putting the record into it, and then patching that collection. This idea is not "complete," and my example above demonstrates that the Patch function is currently broken.

CarlosFigueira
Power Apps

Hi @AIUYM19 - the error message from the Patch function is indeed misleading. What you have in your example is a type mismatch; ideally the Patch function would give a better error for that. The type of NewRecord, as defined in the OnVisible of the screen is a record with two text properties (Value1 and Value2)... In the OnSelect of your dropdown/combobox, you try to assign a record to Value1 (the Selected property of both dropdown and combo box controls return the record that was selected, not only the string that is shown), which cannot be converted to a text value.

You can fix your example by choosing the appropriate property of the Selected record from the dropdown, something along the lines of

UpdateContext({
    NewRecord: Patch(
        NewRecord,
        {
            Field1: Self.Selected.Value
        }
    )
})

Hope this helps!

AIUYM19
Advocate V

@CarlosFigueira 

Yes, I noticed the error in my example after I clicked submit, but I didn't feel it was important enough to amend, because the result is still the same. If you add the .Value to the end of the argument, the Patch function still returns those errors.

planetparker
Frequent Visitor

In my use cases, I typically use create/use variables as objects when I need to track multiple attributes for the same, single instance object.  In these scenario's, I've been able to use this syntax successfully:

Set(myApple, Patch(myApple, {Eaten: true}))

 

However for scenario's where I need to track multiple RECORDS (instances) of the same object, then a collection seems like a much better fit over a multi-record global variable, and easy to update either by row or column.

LeeHarris
Solution Sage

This issue has been sending me round in circles all week where my app would just stop working and complain about issues with the Patch function. Checked and checked again within the documentation and I was using it exactly as described but whenever running the app outside of the editor, it would fall over when patching a record that had originated from Dataverse.

 

The workaround provided by @nathanpsmith is the only way I can get this working in my app.

PeterCBell_au
Frequent Visitor

Managing properties and calculations, and exposing results from calculations for components is a righ royal pain, with all sorts of work arounds (eg. component behaviours that trigger the parent to calculate, etc)

 

Using an idea from elsewhere, the use of a record within a component to defined various fields is very useful. For example, custom input property IO as a record.

  • Lets say the IO record is {LabelText:"LNMP",LNMPdate:Today(),CycleLength:28,EDD:Today()}
  • This all works well within the component. eg. the default value of a label might be MyComponent.IO.LabelText, and the default text for a text control might be MyComponent.IO.CycleLength

All fine so far.

If my component wants to perform some calculations that are visible to the parent, then what I should be able to do is (as originally suggested) is patch a record that isnt part of a table or collection.

 

For example (pregnancy due date from last period). From within the component

  • OnChange for TextBox --> Patch(Blank(),MyComponent.IO,{CycleLength:Value(Self.Text),});Patch(Blank(),MyComponent.IO,{EDD:DateAdd(MyComponent.IO.LNMPdate,280 + (MyComponent.IO.CycleLength-28)})

In this example, the parent hosting the control can at all times access raw data (eg. MyComponent1.IO.CycleLength) and results of calculations (eg. MyComponent1.IO.LNMPdate) or externally modify the data used by the component (eg. Patch(Blank(),MyComponent1.IO

 

I cant see any of the work arounds doing the trick for components, since I cant do a global Set() from within a component.

What I can see is that allowing Patch for an isolated record would have many uses, within and outside components.

It seems that copying a record to a collection, patching the collection, and then retrieving the first record of the modified collection is at best kludgy, error prone (especially with async operations), and memory/cycle intensive.

I hope that this can be considered for implementation.

Regards

Peter