question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ForEach only works for the first item

See original GitHub issue

Hi,

I’ve been trying to get a for-each loop to work that just writes the items of a list to the console. image

The Dummy Data Generator returns a List<Dictionary<string, string>> as Output. image

I use Javascript: (input) for both the ForEach Items param and the WriteLine Text param.

The expected outcome is that all my list entries are printed to the console, but what actually happens is that the first entry is successfully printed and then an exception is thrown: image

Hopefully somebody can help me with this 😃

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
sfmskywalkercommented, Oct 4, 2021

I see now. The issue is the use of the input variable, which changes over time.

For example, initially, input will hold the list of dictionaries (the output of the custom activity). Next, as the ForEach activity executes, it changes the input value to the item of the current iteration (a dictionary).

Once an iteration completes, ForEach is executed again, which will re-evaluate its Items property. But since this expression uses input, it is no longer the original list of dictionaries.

To fix this, you need to perform the following steps:

  1. Update your custom activity by adding an output property (call it e.g. Output).
  2. Then, instead of setting context.Output, set the result to the new Output property.
  3. Update the ForEach items JS expression to: activities.TestDataSource1.Output().
  4. Remove the connection between the WriteLine and the ForEach activity; Elsa will automatically execute the ForEach activity for you after its Iterate branch completes.

Here is the updated activity code:

[ActivityAttribute(
    Category = "Data Source",
    DisplayName = "Test",
    Description = "Fetch dummy data.",
    Outcomes = new[] { OutcomeNames.Done }
)]
public class TestDataSource : Activity
{
    [ActivityInput(Hint = "Number of entries")]
    public int EntryAmount { get; set; }

    [ActivityInput(Hint = "Number of columns")]
    public int Columns { get; set; }

    // Added.
    [ActivityOutput] public IList<Dictionary<string, object>> Output { get; set; } = default!;

    protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
    {
        try
        {
            var result = new List<Dictionary<string, object>>();
            for (int i = 0; i < EntryAmount; i++)
            {
                var entry = new Dictionary<string, object>();
                for (int j = 0; j < Columns; j++)
                {
                    entry.Add($"key{j + i * 10}", $"value{j + i * 10}");
                }

                result.Add(entry);
            }

            // Updated.
            Output = result;

            return Done();
        }
        catch (Exception e)
        {
            throw new ActivityException("Creating Test data failed!", e);
        }
    }
}

And here is the updated workflow JSON:

{
  "$id": "1",
  "definitionId": "f78b6f6a0e554c5fbca44fb5bee0c321",
  "versionId": "91e42f8754a949b6aa5e64b1f2f92c96",
  "name": "loop_test_data",
  "displayName": "Loop test data",
  "version": 5,
  "variables": {
    "$id": "2",
    "data": {}
  },
  "customAttributes": {
    "$id": "3",
    "data": {}
  },
  "isSingleton": false,
  "persistenceBehavior": "WorkflowBurst",
  "deleteCompletedInstances": false,
  "isPublished": true,
  "isLatest": true,
  "activities": [
    {
      "$id": "4",
      "activityId": "32e64fb2-94ad-40a0-9f4e-2d6f1df771d9",
      "type": "TestDataSource",
      "name": "TestDataSource1",
      "displayName": "Test",
      "persistWorkflow": false,
      "loadWorkflowContext": false,
      "saveWorkflowContext": false,
      "properties": [
        {
          "$id": "5",
          "name": "EntryAmount",
          "expressions": {
            "$id": "6",
            "Literal": "50"
          }
        },
        {
          "$id": "7",
          "name": "Columns",
          "expressions": {
            "$id": "8",
            "Literal": "5"
          }
        }
      ],
      "propertyStorageProviders": {}
    },
    {
      "$id": "9",
      "activityId": "4e346ab0-bcb0-4d5f-b175-0a5739f53e85",
      "type": "WriteLine",
      "displayName": "Write Line",
      "persistWorkflow": false,
      "loadWorkflowContext": false,
      "saveWorkflowContext": false,
      "properties": [
        {
          "$id": "10",
          "name": "Text",
          "syntax": "JavaScript",
          "expressions": {
            "$id": "11",
            "JavaScript": "(input)"
          }
        }
      ],
      "propertyStorageProviders": {}
    },
    {
      "$id": "12",
      "activityId": "439b8305-22a7-4d87-9af6-6fe9c17879af",
      "type": "WriteLine",
      "displayName": "Write Line",
      "persistWorkflow": false,
      "loadWorkflowContext": false,
      "saveWorkflowContext": false,
      "properties": [
        {
          "$id": "13",
          "name": "Text",
          "expressions": {
            "$id": "14",
            "Literal": "SUCCESS"
          }
        }
      ],
      "propertyStorageProviders": {}
    },
    {
      "$id": "15",
      "activityId": "7b1a127b-7da6-4006-af17-754dcd64878c",
      "type": "ForEach",
      "displayName": "For Each",
      "persistWorkflow": false,
      "loadWorkflowContext": false,
      "saveWorkflowContext": false,
      "properties": [
        {
          "$id": "16",
          "name": "Items",
          "syntax": "JavaScript",
          "expressions": {
            "$id": "17",
            "Literal": "(input)",
            "JavaScript": "activities.TestDataSource1.Output()"
          }
        }
      ],
      "propertyStorageProviders": {}
    }
  ],
  "connections": [
    {
      "$id": "18",
      "sourceActivityId": "32e64fb2-94ad-40a0-9f4e-2d6f1df771d9",
      "targetActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c",
      "outcome": "Done"
    },
    {
      "$id": "19",
      "sourceActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c",
      "targetActivityId": "4e346ab0-bcb0-4d5f-b175-0a5739f53e85",
      "outcome": "Iterate"
    },
    {
      "$id": "20",
      "sourceActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c",
      "targetActivityId": "439b8305-22a7-4d87-9af6-6fe9c17879af",
      "outcome": "Done"
    }
  ],
  "id": "91e42f8754a949b6aa5e64b1f2f92c96"
}

I will close this issue as solved, but feel free to follow-up with any questions or concerns.

1reaction
Oraeyacommented, Sep 24, 2021

I upgraded all Elsa packages to 2.3.0 but it still throws the same exception. Here is the exported Workflow JSON: { "$id": "1", "definitionId": "371ae20403c34965be434a5584216ad5", "versionId": "060cc3b9ad5d469ba7997dbba772ae53", "name": "loop_test_data", "displayName": "Loop test data", "version": 10, "variables": { "$id": "2", "data": {} }, "customAttributes": { "$id": "3", "data": {} }, "isSingleton": false, "persistenceBehavior": "WorkflowBurst", "deleteCompletedInstances": false, "isPublished": true, "isLatest": true, "activities": [ { "$id": "4", "activityId": "e8c51f8c-1118-4a07-9db0-10dfd70e4ee5", "type": "HttpEndpoint", "displayName": "HTTP Endpoint", "persistWorkflow": false, "loadWorkflowContext": false, "saveWorkflowContext": false, "properties": [ { "$id": "5", "name": "Path", "expressions": { "$id": "6", "Literal": "/loop-test" } }, { "$id": "7", "name": "Methods", "expressions": { "$id": "8", "Json": "[\"GET\"]" } }, { "$id": "9", "name": "ReadContent", "expressions": { "$id": "10" } }, { "$id": "11", "name": "TargetType", "expressions": { "$id": "12" } } ], "propertyStorageProviders": {} }, { "$id": "13", "activityId": "32e64fb2-94ad-40a0-9f4e-2d6f1df771d9", "type": "TestDataSource", "displayName": "Test", "persistWorkflow": false, "loadWorkflowContext": false, "saveWorkflowContext": false, "properties": [ { "$id": "14", "name": "EntryAmount", "expressions": { "$id": "15", "Literal": "50" } }, { "$id": "16", "name": "Columns", "expressions": { "$id": "17", "Literal": "5" } } ], "propertyStorageProviders": {} }, { "$id": "18", "activityId": "4e346ab0-bcb0-4d5f-b175-0a5739f53e85", "type": "WriteLine", "displayName": "Write Line", "persistWorkflow": false, "loadWorkflowContext": false, "saveWorkflowContext": false, "properties": [ { "$id": "19", "name": "Text", "syntax": "JavaScript", "expressions": { "$id": "20", "JavaScript": "(input)" } } ], "propertyStorageProviders": {} }, { "$id": "21", "activityId": "439b8305-22a7-4d87-9af6-6fe9c17879af", "type": "WriteLine", "displayName": "Write Line", "persistWorkflow": false, "loadWorkflowContext": false, "saveWorkflowContext": false, "properties": [ { "$id": "22", "name": "Text", "expressions": { "$id": "23", "Literal": "SUCCESS" } } ], "propertyStorageProviders": {} }, { "$id": "24", "activityId": "7b1a127b-7da6-4006-af17-754dcd64878c", "type": "ForEach", "displayName": "For Each", "persistWorkflow": false, "loadWorkflowContext": false, "saveWorkflowContext": false, "properties": [ { "$id": "25", "name": "Items", "syntax": "JavaScript", "expressions": { "$id": "26", "Literal": "(input)", "JavaScript": "(input)" } } ], "propertyStorageProviders": {} } ], "connections": [ { "$id": "27", "sourceActivityId": "e8c51f8c-1118-4a07-9db0-10dfd70e4ee5", "targetActivityId": "32e64fb2-94ad-40a0-9f4e-2d6f1df771d9", "outcome": "Done" }, { "$id": "28", "sourceActivityId": "32e64fb2-94ad-40a0-9f4e-2d6f1df771d9", "targetActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c", "outcome": "Done" }, { "$id": "29", "sourceActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c", "targetActivityId": "4e346ab0-bcb0-4d5f-b175-0a5739f53e85", "outcome": "Iterate" }, { "$id": "30", "sourceActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c", "targetActivityId": "439b8305-22a7-4d87-9af6-6fe9c17879af", "outcome": "Done" }, { "$id": "31", "sourceActivityId": "4e346ab0-bcb0-4d5f-b175-0a5739f53e85", "targetActivityId": "7b1a127b-7da6-4006-af17-754dcd64878c", "outcome": "Done" } ], "id": "060cc3b9ad5d469ba7997dbba772ae53" }

And the code for my Activity:

using System;
using System.Collections.Generic;
using Elsa;
using Elsa.ActivityResults;
using Elsa.Attributes;
using Elsa.Services;
using Elsa.Services.Models;
using ElsaQuickstarts.Server.DashboardAndServer.Exceptions;

namespace ElsaQuickstarts.Server.DashboardAndServer.Activities.DataSources
{
    [Activity(
        Category = "Data Source",
        DisplayName = "Test",
        Description = "Fetch dummy data.",
        Outcomes = new[] {OutcomeNames.Done}
    )]
    public class TestDataSource : Activity
    {
        [ActivityInput(Hint = "Number of entries")]
        public int EntryAmount { get; set; }

        [ActivityInput(Hint = "Number of columns")]
        public int Columns { get; set; }

        protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
        {
            try
            {
                var result = new List<Dictionary<string, object>>();
                for (int i = 0; i < EntryAmount; i++)
                {
                    var entry = new Dictionary<string, object>();
                    for (int j = 0; j < Columns; j++)
                    {
                        entry.Add($"key{j + i * 10}", $"value{j + i * 10}");
                    }

                    result.Add(entry);
                }

                context.Output = result;
                return Done();
            }
            catch (Exception e)
            {
                throw new ActivityException("Creating Test data failed!", e);
            }
        }
    }
}

And my custom Exception:

using System;
using Elsa.Services.Models;

namespace ElsaQuickstarts.Server.DashboardAndServer.Exceptions
{
    public class ActivityException : Exception
    {
        public ActivityException() : base()
        {
        }

        public ActivityException(string message)
            : base(message)
        {
        }

        public ActivityException(string message, Exception inner)
            : base(message, inner)
        {
        }
    }
}

@sfmskywalker I hope you can reproduce the error with this 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why is the ForEach only registering the first element from ...
The querySelector returns a static NodeList. So when this code is run, probably only one element is rendered in the page.
Read more >
Foreach is only returning the first value
I am currently building a store and i am using Crinsane package but i found out that after trying to iterate over the...
Read more >
Why the forEach JavaScript Method Might Not Always be ...
In the first case, forEach wouldn't work at all since there's no way to exit it, and in the latter, you might get...
Read more >
Why is it that the first Element is returned in forEach loop?
The forEach method actually has no return value so it will always return undefined. Try using .map() instead. Posting to the forum ...
Read more >
How to treat first item in a foreach (or similar) different than the ...
Simply put, it checks if there is just one organization for each candidate row. If it's only one, then it copies that organization...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found