Question

How do I save a form without using a submission button (I have another trigger on the page that can be used to run the saving code). The form is never shown to the user, I just need it to save to a web forms for marketers database, unless there is a smarter way of course.

I can get it out just fine using

Sitecore.Forms.Core.Data.FormItem form =
 Sitecore.Forms.Core.Data.FormItem.GetForm(formID);

However, I want to

  1. Change the data in the forms fields

(i.e. something like)

form.Fields["Name"] = "Test name"; 
// this wont work, I dont know how to access the field's value before I store it.
  1. Save the form data in the web form for marketers-item's database in sitecore.

After I have modified the fields, I would like to save it of course.

Was it helpful?

Solution

The way to do it was to first get a copy of the form, set its fields using a list of AdaptedControlResult and save it using InsertForm. This way it ends up in the WFFM's data table correctly.

The customerInfo used in the code, is from a CartHelper, but it could be anything.

Code:

string formID = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}";
DataUri uri = new DataUri(new ID(formID));
Sitecore.Data.Items.Item formItem = Sitecore.Context.Database.GetItem(uri);

// if the item exists, run through all the known fields and add the values from the customerinfo into them.
if (formItem != null)
{
   List<AdaptedControlResult> acrList = new List<AdaptedControlResult>();
   Sitecore.Data.Items.Item[] fieldItems = formItem.Axes.GetDescendants();

   foreach (Sitecore.Data.Items.Item fieldItem in fieldItems) //.Where(x => x.TemplateName == "Field"))
   {
      if (fieldItem.Name == "E-mail")
      {
         acrList.Add(new AdaptedControlResult(new ControlResult(fieldItem.Name, System.Web.HttpUtility.UrlDecode(customerInfo.Email), string.Empty) { FieldID = fieldItem.ID.ToString(), FieldName = fieldItem.Name, Value = System.Web.HttpUtility.UrlDecode(customerInfo.Email) }, true));
         continue;
      }

   // same for all other fields.
   }

   // save data
   if (acrList.Count > 0)
   {
      AdaptedResultList arl = new AdaptedResultList(acrList);

      try
      {
         Sitecore.Forms.Data.DataManager.InsertForm(formItem.ID, arl, Sitecore.Data.ID.NewID, null);
      }
      catch (Exception ex)
      {
         // Log data here
      }
   }
}

OTHER TIPS

If you are trying to programmatically submit data to a WFFM table in the DB, you can use the following:

Say you have your list of fields populated in a list of this class:

public class WffmField
    {
        public string FieldName { get; set; }
        public string FieldGuid { get; set; }
        public string FieldValue { get; set; }
    }

the field guid would be the guid from sitecore: enter image description here

You can then save to the WFFM database:

// This should be populated with the data you want to send to the WFFM database
var fields = new List<WffmField>(); 
var wffmDatabaseFields = fields.Select(GetWFFMDatabaseField).ToList();

Sitecore.Forms.Data.DataManager.InsertForm(
    formId: new Sitecore.Data.ID("<Form guid here>"),
    fields: new AdaptedResultList(wffmDatabaseFields),
    sessionID: AnalyticsTracker.SessionId,
    data: null);

Hope this helps!

If I understand your question right; you're mixing up two principles here. You want to make a form go through it's own separate submission routines - but it also looks like you're attempting to write your own form submission, using server side code that will never Work in the manner you describe.

The best approach to making a WFM submit from another control on the page, is to have it still use a "Submit" type of button on the form, but use CSS to hide the actual control. It has a distinct css class you can use to hide it. Then - from the other area of your page you want to control the submit, fire off the hidden control's OnClick event to get the form posting back and saving the content.

Your code; the way I read it; is trying to read the Sitecore Form Item and then access that Sitecore item's Fields Collection. This collection of fields has nothing to do directly with your form, and would never hold the actual data the user on the site is currently entering.

I've recently had a similar requirement to this question. The answer above from Jesper Hoff is great if all you need to do is get the form data saved into the configured database for WFfM. However what it doesn't do is honour the Save Actions associated with the form. So it's fine if you want to record submissions into SQL Server, but it doesn't help if you need to send them in an email, or transmit them to a CRM. I needed to make email sending work in the code I was working on, so have done a bit more digging into the innards of WFfM:

If you want your code-based submission to honour the configured Save Actions for a form then you need to make three key changes to the code above:

  • Firstly you need to make use of the Sitecore.Form.Core.Submit.SubmitActionManager.Execute() method rather than Sitecore.Forms.Data.DataManager.InsertForm(). This appears to be what the innards of WFfM call when you post back a valid form.
  • Secondly you need to fetch and configure the set of Save Actions that have been set up for your WFfM for definition. And there's a bit of juggling required to get this data in the right format.
  • And thirdly you need to collect your form data as ControlResult objects not AdaptedControlResult. The data you pass in gets wrapped automatically as part of the call to Execute().

Ignoring error checking for clarity, I ended up with code like this:

List<ControlResult> results = new List<ControlResult>();
results.Add(makeControlResult(_nameFieldID, "Name", "Bob Jones"));
results.Add(makeControlResult(_emailFieldID, "Email", "B.Jones@test.com"));
results.Add(makeControlResult(_messageFieldID, "Message", "Lorem ipsum. Dolor sit amet."));

Item formItem = Sitecore.Context.Database.GetItem(_yourFormID);

SitecoreSimpleForm simpleForm = new SitecoreSimpleForm(formItem);
var saveActionXml = simpleForm.FormItem.SaveActions;
var actionList = Sitecore.Form.Core.ContentEditor.Data.ListDefinition.Parse(saveActionXml);

List<ActionDefinition> actionDefinitions = new List<ActionDefinition>();
actionDefinitions.AddRange(actionList.Groups.SelectMany(x => x.ListItems).Select(li => new ActionDefinition(li.ItemID, li.Parameters) { UniqueKey = li.Unicid }));

Sitecore.Form.Core.Submit.SubmitActionManager.Execute(_formID, results.ToArray(), actionDefinitions.ToArray());

The set of save actions and their configuration is saved in the Item for your form, but you have to wrap the item in a SitecoreSimpleForm object to get it out. What you get back is XML, so you then need to parse it with the Sitecore.Form.Core.ContentEditor.Data.ListDefinition.Parse() method in order to get back a set of deserialised Save Action objects. However, they're not the right sort of objects for the SubmitActionManager so you need to project them into ActionDefinition objects in order to make use of them.

(Note that the Save Action objects you get after parsing the XML aren't in a flat list, so you need to use something like SelectMany() to flatten it before using them)

The makeControlResult() method referenced above is just to make the snippet clearer. It just creates a ControlResult object from the data about a form field:

public ControlResult makeControlResult(string fieldID, string fieldName, string fieldValue)
{
    return new ControlResult(fieldName, fieldValue, string.Empty)
    {
        FieldID = fieldID,
        FieldName = fieldName,
        Value = fieldValue, 
        Parameters = string.Empty
    };
}

Depending on how you're getting hold of your data, you may prefer to use a variation on the method in the other answer to generate this data.

I also wrote up a bit more detail of how I arrived at this answer on my blog. That post also includes a snippet about how to get back any errors that the Save Actions might generate - which can be important when you're using multiple Save Actions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top