Create a dropdown options list from content values instead of Data types
Hello, all
I am fairly new to umbraco and very new to MVC. I have been able to successfully create contact forms using some online tutorials, one of which allowed a drop-down list to be generated from the data types in back office.
This is great, but I want to be able to use user entered content values to generate the values in the list. I am hoping there is an easy way to do this.
the content I want to use would be location contact information. I would like the User to enter location data including name and email address, and the contact form would use the location name to populate the drop-down list, and the selected value from that list be used to send the message to.
Here is the piece of the Surface Controller that is currently using the Datatype... how can this be changed to use content values?
// This will generate dropdown values from Data Type Created in Umbraco---- only needed if using dropdownlist
List<SelectListItem> ListOfLocations = new List<SelectListItem>();
XPathNodeIterator iterator = umbraco.library.GetPreValues(1091);//Id of Datatype
iterator.MoveNext();
XPathNodeIterator preValues = iterator.Current.SelectChildren("companyName", "");
while (preValues.MoveNext())
{
string preValue = preValues.Current.Value;
ListOfLocations.Add(new SelectListItem
{
Text = preValue,
Value = preValue
});
myModel.ListOfLocations = ListOfLocations;
}
// End Dropdown Values
When creating things such as dropdowns for forms: I prefer to create sub-nodes that support the dropdown or have a repository structure that I may reference if I need to use it multiple times.
This allows the user to recreate as many sub items as required. While I can populate a simple foreach loop to iterate through the options for presentation.
<select>
@foreach (child in Model.Content.Children){
<option value="@child.key">@child.friendlyname</option>
}
</select>
Then on submit I can look up additional details on the contact based on the option or key submitted.
//umbraco.NodeFactory.Node
var node = new Node (submittednodeid);
node.GetProperty("propertyName").Value
I have the location Information set up as a repository Structure... the user can add as many locations as they like.
I need the surface controller and model to generate the select list in the view based off of the companyName Values of the document Type.
this is my current attempt in which I am getting issues using the Get Property method.
ContactMultiLocModel myModel = new ContactMultiLocModel();
// This will generate dropdown values from Data Type Created in Umbraco---- only needed if using dropdownlist
List<SelectListItem> ListOfLocations = new List<SelectListItem>();
var AllLocations = umbraco.uQuery.GetNodeByUrl("/location-information");
var Location = AllLocations.GetDescendantNodesByType("locationInfo");
XPathNodeIterator iterator = Location.GetProperty("companyName").Value;
iterator.MoveNext();
XPathNodeIterator locValues = iterator;
while (locValues.MoveNext())
{
string locValue = locValues.Current.Value;
ListOfLocations.Add(new SelectListItem
{
Text = locValue,
Value = locValue
});
myModel.ListOfLocations = ListOfLocations;
}
Chris, Thanks so much for your help. I was able to get the form rendered with the values from the document type. If I could pick your brain a little more, I am now having trouble posting the selected value back to Umbraco.
Here is how the list is generated now:
ContactMultiLocModel myModel = new ContactMultiLocModel();
// This will generate dropdown values
List<SelectListItem> ListOfLocations = new List<SelectListItem>();
var AllLocations = umbraco.uQuery.GetNodeByUrl("/location-information");
var Locations = AllLocations.ChildrenAsList.Where(n => n.NodeTypeAlias == "locationInfo");
foreach (var node in Locations)
{
ListOfLocations.Add(new SelectListItem
{
Text = node.GetProperty("locationName").Value,
Value = node.GetProperty("locationEmail").Value
});
}
myModel.ListOfLocations = ListOfLocations;
// End Dropdown Values
And this is where I am trying to post the Text of the selected item... I will also need the value later on for the "to" email address. As you can see by the question marks I am not even sure I am headed in the right direction.
if (ModelState.IsValid) // For Field Validation
{
// This will post submittion to Umbraco Database
var newContact = Services.ContentService.CreateContent(model.Name + "-" + DateTime.Now, CurrentPage.Id, "contactFormula");
var myService = ApplicationContext.Services.DataTypeService;
var SelectedLocation = myService.GetAllDataTypeDefinitions().First(x => x.Name == "Location");
int SelcetedLocationText = myService.GetPreValuesByDataTypeId(SelectedLocation.Id)???
newContact.SetValue("CFName", model.Name);
newContact.SetValue("CFEmail", model.Email);
newContact.SetValue("CFCompany", model.Company);
newContact.SetValue("CFLocation", SelcetedLocationText);
newContact.SetValue("CFMessage", model.Message);
Services.ContentService.SaveAndPublishWithStatus(newContact);
...
If you are looking to post content back into Umbraco then content service is the right approach.
The following line does seem out of place. I don't understand what you are trying to get access to with this call:
int SelcetedLocationText = myService.GetPreValuesByDataTypeId(SelectedLocation.Id)???
Let's rethink our approach to the form submission to allow ourselves more flexibility:
Change This:
ListOfLocations.Add(new SelectListItem
{
Text = node.GetProperty("locationName").Value,
Value = node.GetProperty("locationEmail").Value
});
To :
ListOfLocations.Add(new SelectListItem
{
Text = node.GetProperty("locationName").Value,
Value = node.Id // This allows us to lookup a node for further content creation
});
Now when we submit this form we can pull details about the location and build references/content from the referenced node as needed.
var location = new Node (submittednodeid);
//attach the name:
newContact.SetValue("CFLocation", location.Name);
//OR attach the node reference itself if it is a reference/int data type
newContact.SetValue("CFLocation", location.Id);
//OR iterate through the properties with a stringBuilder and supply richtext.
var sb = new stringbuilder();
//for each property in node.properties.
//append property.value to sb
//append rich formatting to sb
//}
newContact.SetValue("CFLocation", sb.ToString());
Hope this helps please clarify if I didn't grasp what you were after.
Just for Reference here is the controller after all is working. I was able to create dropdown from content of a specific document type. The selected value was then used to post the data back to umbraco, and controlled where the email was sent to.
using MyKit.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
using Umbraco.Web;
using System.Text;
using System.Net.Mail;
using umbraco.NodeFactory;
namespace MyKit.Controllers
{
public class ContactMultiLocSurfaceController : SurfaceController
{
public ActionResult ShowForm()// links controller to template/macro
{
ContactMultiLocModel myModel = new ContactMultiLocModel();
// This will generate dropdown values
List<SelectListItem> ListOfLocations = new List<SelectListItem>();
var AllLocations = umbraco.uQuery.GetNodeByUrl("/location-information");
var Locations = AllLocations.ChildrenAsList.Where(n => n.NodeTypeAlias == "locationInfo");
foreach (var node in Locations)
{
ListOfLocations.Add(new SelectListItem
{
Text = node.GetProperty("locationName").Value,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
myModel.ListOfLocations = ListOfLocations;
// End Dropdown Values
return PartialView("ContactMultiLocForm", myModel); // Links to Partial View
}
public ActionResult HandleFormPost(ContactMultiLocModel model) //Links functions to the form in the partial view...BeginUmbracoForm
{
if (ModelState.IsValid) // For Field Validation
{
// This will post submittion to Umbraco Database
var newContact = Services.ContentService.CreateContent(model.Name + "-" + DateTime.Now, CurrentPage.Id, "contactFormula");
var myService = ApplicationContext.Services.DataTypeService;
int LocationValue = model.Location;
var LocationNode = new Node(LocationValue);
newContact.SetValue("CFName", model.Name);
newContact.SetValue("CFEmail", model.Email);
newContact.SetValue("CFCompany", model.Company);
newContact.SetValue("CFLocation", LocationNode.Name);
newContact.SetValue("CFMessage", model.Message);
Services.ContentService.SaveAndPublishWithStatus(newContact);
//This will compose and send email
var sb = new StringBuilder();
sb.AppendFormat("<p>Name: {0}</p>", model.Name);
sb.AppendFormat("<p>Email: {0}</p>", model.Email);
sb.AppendFormat("<p>Company: {0}</p>", model.Company);
sb.AppendFormat("<p>Location: {0}</p>", LocationNode.Name);
sb.AppendFormat("<p>Message: {0}</p>", model.Message);
SmtpClient smtp = new SmtpClient("host.com", 587);
smtp.Credentials = new System.Net.NetworkCredential("***@website.net", "***");
smtp.EnableSsl = true;
MailMessage message = new MailMessage();
message.To.Add(LocationNode.GetProperty("locationEmail").Value);
message.Subject = "Message from Website";
message.From = new MailAddress(model.Email);
message.Body = sb.ToString();
message.IsBodyHtml = true;
try
{
smtp.Send(message);
}
catch (SmtpException)
{
TempData["Failed"] = true;
return RedirectToCurrentUmbracoPage();
}
TempData["Success"] = true;
return RedirectToCurrentUmbracoPage();
}
return RedirectToCurrentUmbracoPage();
}
}
}
the Key to this working where the following lines:
int LocationValue = model.Location;
var LocationNode = new Node(LocationValue);
Create a dropdown options list from content values instead of Data types
Hello, all
I am fairly new to umbraco and very new to MVC. I have been able to successfully create contact forms using some online tutorials, one of which allowed a drop-down list to be generated from the data types in back office.
This is great, but I want to be able to use user entered content values to generate the values in the list. I am hoping there is an easy way to do this.
the content I want to use would be location contact information. I would like the User to enter location data including name and email address, and the contact form would use the location name to populate the drop-down list, and the selected value from that list be used to send the message to.
Here is the piece of the Surface Controller that is currently using the Datatype... how can this be changed to use content values?
Thanks for your time.
Does anyone have any Info on this?
When creating things such as dropdowns for forms: I prefer to create sub-nodes that support the dropdown or have a repository structure that I may reference if I need to use it multiple times.
This allows the user to recreate as many sub items as required. While I can populate a simple foreach loop to iterate through the options for presentation.
Then on submit I can look up additional details on the contact based on the option or key submitted.
I have the location Information set up as a repository Structure... the user can add as many locations as they like.
I need the surface controller and model to generate the select list in the view based off of the companyName Values of the document Type.
this is my current attempt in which I am getting issues using the Get Property method.
I think I understand although not familiar with the XpathNodeIterator approach.
So if it is read only then you should be able to iterate and build your list with the following using linq:
I get the following errors with the code you supplied:
CS1929 C# does not contain a definition for 'Where' and the best extension method overload requires a receiver of type
CS1660 C# Cannot convert lambda expression to type 'string' because it is not a delegate type
My bad, writing code without a intellisense is a recipe for forum pain :
Chris, Thanks so much for your help. I was able to get the form rendered with the values from the document type. If I could pick your brain a little more, I am now having trouble posting the selected value back to Umbraco.
Here is how the list is generated now:
And this is where I am trying to post the Text of the selected item... I will also need the value later on for the "to" email address. As you can see by the question marks I am not even sure I am headed in the right direction.
Hi Sam,
Sorry for the delay.
If you are looking to post content back into Umbraco then content service is the right approach.
The following line does seem out of place. I don't understand what you are trying to get access to with this call:
Let's rethink our approach to the form submission to allow ourselves more flexibility:
Change This:
To :
Now when we submit this form we can pull details about the location and build references/content from the referenced node as needed.
Hope this helps please clarify if I didn't grasp what you were after.
That clears it up for me, Thanks for the extra Info.
Just for Reference here is the controller after all is working. I was able to create dropdown from content of a specific document type. The selected value was then used to post the data back to umbraco, and controlled where the email was sent to.
the Key to this working where the following lines:
is working on a reply...