5

In a lightning component, the recommended way to store data is in an <aura:attribute>. If I store a rich structure in an attribute and want to modify just some specific values, what is the recommended approach for making modifications? Consider the following data stored in an attribute named tableData.

{
  columns: [
    "Name",
    "Phone",
    "Email"
  ],
  rows: [{
      isSelected: false,
      fields: [
        "John",
        "415-555-1234",
        "j@me.com"
      ]
    },
    {
      isSelected: false,
      fields: [
        "Alex",
        "631-555-1234",
        "a@me.com"
      ]
    }
  ]
}

For a simple example, let's say I am in a controller function and want to set the isSelected field to true on the second row. I can get the data in my function by calling var tableData = component.get('v.tableData')' but this does not appear to be by reference. Modifying the resulting object does not change anything back in the view. I can update the view by calling component.set('v.tableData', tableData) after making my changes but this causes the whole table to be re-drawn in the view which gets really slow really quickly.

I figure there has to be a better way to do this since in any other modern javascript framework I am able to access a specific part of my scope and update a property to result in a very small redraw in the UI. Does anyone either have suggestions or have any links to documentation that discusses the preferred way to work with data structures as attributes in a lightning component?

5

You're not required to get and set the entire attribute each time. You can perform more granular updates, and you'll get better responsiveness. For your example, if you wanted to set the second row's isSelected attribute to true, you're allowed to do this:

component.set("v.tableData.rows[1].isSelected", true);

This will make sure that the only the appropriate notifications are sent. You can be as granular as you'd like to be, as long as the first parameter is a legitimate target, it'll update correct and affect a smaller region based on which components are interested in changes to the affected data.

Also, in a more complicated example, the rows attribute itself would be bound to some sort of component; if possible, consider updating values within the component. For example, it might be bound to a checkbox:

<ui:inputCheckbox value="{!row.isSelected}" />

When the user checks the box, the isSelected attribute is updated, and the effect ripples through the framework, but only items that directly work with that row's isSelected checkbox will be affected.

The Lightning framework depends heavily on a lot of smaller components, so you should very rarely be manipulating large objects as a whole. Having several smaller components built that all add up to a total UI tends to lead to better data isolation, smaller UI refreshes, and faster updates overall.

| improve this answer | |
  • Awesome, I was not aware that I could provide a more granular syntax. Do you know if they have any documentation outlining what is supported? For example, I doubt objects/keys are supported since those do not work in expressions. We usually make smaller components when the component will be used more than once, but it seems like a lot of overhead to make sub-components for a larger component that will only be used in this single context. If this results in much better performance or easier maintenance though I would certainly change my mind on that. – dsharrison Aug 4 '17 at 0:14
  • @dsharrison You're right, you can only access things you could get away with in expressions. However, we do get some extra flexibility in JavaScript, as we could write component.set("v.tableData.rows["+i+"].isSelected", value). In general, though, we get better performance the more granular you can be. – sfdcfox Aug 4 '17 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.