I am trying to make a NameValueList collection editable with GlassMapper and I don't seem to be able to get to the bottom of this.
We have a list of validations that can be attached to a field and I would like to have the validation message editable in ExperienceEditor.
The collection is pre-processed when GlassMapper is retrieving the item:
Validations = glassItem.GetValidations();
#foreach(Validation validation in Model.Validations)
{
<div id="#validation.Identifier" ng-message="#validation.AngularKey" ng-cloak class="mtg-validation-msg">
#Html.Glass().Editable(validation, e => e.ErrorMessage)
</div>
}
Error that I am getting:
Failed item resolve - You cannot save a class that does not contain a property that represents the item ID. Ensure that at least one property has been marked to contain the Sitecore ID. Type: MyAssembly.Models.Validation
It is not possible to directly edit certain types of complex fields in the Experience Editor, such as Treelist, Multilist or Name Value Collection.
Instead, you should set up and use an Edit Frame. This will pop up a modal dialog allowing you to edit the field, it is not inline but means you do not need to leave the Experience Editor. This is the recommended approach to this problem.
Since you are using Glass Mapper, since version 4 you can declare Edit Frames all directly from code and now have to declare/set them up in the Core database first.
#if (Sitecore.Context.PageMode.IsExperienceEditor)
{
using (Html.Glass().BeginEditFrame(Model, "Edit", x => x.Validations))
{
<div>Edit Validations</div>
}
}
You might be interested in this blog post I wrote about adding a wrapper around the Edit Frame to make the UX more friendly.
Related
I have a form which I am validating using CFWheels model validation and form helpers.
My code for index() Action/View in controller:
public function index()
{
title = "Home";
forms = model("forms");
allforms = model("forms").findAll(order="id ASC");
}
#startFormTag(controller="form", action="init_form")#
<select class="form-control">
<option value="">Please select Form</option>
<cfloop query="allforms">
<option value="#allforms.id#">#allforms.name#</option>
</cfloop>
</select>
<input type="text" name="forms[name]" value="#forms.name#">
#errorMessageOn(objectName="forms", property="name")#
<button type="submit">Submit</button>
#endFormTag()#
This form is submitted to init_form() action and the code is :
public function init_form()
{
title = "Home";
forms = get_forms(params.forms);
if(isPost())
{
if(forms.hasErrors())
{
// don't want to retype allforms here ! but index page needs it
allforms = model(tables.forms).findAll(order="id ASC");
renderPage(action="index");
//redirectTo(action="index");
}
}
}
As you can see from the above code I am validating the value of form field and if any errors it is send to the original index page. My problem is that since I am rendering page, I also have to retype the other variables that page need such as "allforms" in this case for the drop down.
Is there a way not to type such variables? And if instead of renderPage() I use redirectTo(), then the errors don't show? Why is that?
Just to be clear, I want to send/redirect the page to original form and display error messages but I don't want to type other variables that are required to render that page? Is there are way.
Please let me know if you need more clarification.
This may seem a little off topic, but my guess is that this is an issue with the form being rendered using one controller (new) and processed using another (create) or in the case of updating, render using edit handle form using update.
I would argue, IMHO, etc... that the way that cfWheels routes are done leaves some room for improvement. You see in many of the various framework's routing components you can designate a different controller function for POST than your would use for GET. With cfWheels, all calls are handled based on the url, so a GET and a POST would be handled by the same controller if you use the same url (like when a form action is left blank).
This is the interaction as cfwheels does it:
While it is possible to change the way it does it, the documentation and tutorials you'll find seem to prefer this way of doing it.
TL; DR;
The workaround that is available, is to have the form be render (GET:new,edit) and processing (POST:create,update) handled by the same controller function (route). Within the function...
check if the user submitted using POST
if it is POST, run a private function (i.e. handle_create()) that handles the form
within the handle_create() function you can set up all your error checking and create the errors
if the function has no errors, create (or update) the model and optionally redirect to a success page
otherwise return an object/array of errors
make the result error object/array available to view
handle the form creation
In the view, if the errors are present, show them in the form or up top somewhere. Make sure that the form action either points to self or is empty. Giving the submit button a name and value can also help in determining whether a form was submitted.
This "pattern" works pretty well without sessions.
Otherwise you can use the Flash, as that is what it was created for, but you do need to have Sessions working. their use is described here: http://docs.cfwheels.org/docs/using-the-flash and here:http://docs.cfwheels.org/v1.4/docs/flashmessages
but it really is as easy as adding this to your controller
flashInsert(error="This is an error message.");
and this to your view
<cfif flashKeyExists("error")>
<p class="errorMessage">
#flash("error")#
</p>
</cfif>
In Sitecore WFFM(Web Form for Marketers) - Can we add hidden field at runtime - i.e. on Submit Action and assign some value to the hidden field.
I also want to reuse this value if there is an exception on the form and user resubmits the form.
Product Details - 7.2 rev. 141226 , Web Forms for Marketers 2.4 rev.140117
As the very simple, you may create hidden field like this (of course, you may provide alternative and more complex bespoke behavior for your hidden field):
public class HiddenField : SingleLineText
{
protected override void DoRender(System.Web.UI.HtmlTextWriter writer)
{
this.textbox.Parent.Parent.Visible = false;
base.DoRender(writer);
}
}
With the next step you need to register that field with WFFM. In order to do that just create an item for your new field:
/sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Custom/Hidden Field
Within that item you specify assembly and class name for that hidden field, as is very common way to Sitecore.
So far, so good. Now you can use your hidden field as others, including adding them programmatically.
P.S. Unfortunately, I do not have an example of code for adding fields programmatically at the moment. However you can try finding that yourself with Reflector, dotPeek or any other disassembling tool. Library should be in your \bin folder already, called Sitecore.Forms.Core.dll
Sitecore 6.6 Update 4
We're using CustomItemGenerator 1.0 and I was using this to help build a primary navigation menu for a site. This worked as expected and everything was rendered properly.
My problem is when I attempt to edit the menu via Page Editor; I don't even see the menu.
I use a repeater and repeat over a list of links to include in the nav. Due to the way the HTML was created, each LI element needs to have its own, specific ID ("Nav Id" Field in Sitecore) that ties into the CSS. Code inside of my repeater's ItemDataBound event:
// Cast the item using CustomItemGenerator-generated class
GenericContentPageItem navItem = (GenericContentPageItem)e.Item.DataItem;
liMenuItem.ID = navItem.NavId.Rendered; // I tried "navItem.NavId" by itself as well
So while this renders properly in the browser, it doesn't when I'm in Page Editor:
<li id="<input id='fld_B72EB6696DCF41A49671972D5EA5DEB8_2163B90C08AB4A18970A7F3ECE79DCFC_en_1_f71bd37d18d146c19e222e89fcffe278_3' class='scFieldValue' name='fld_B72EB6696DCF41A49671972D5EA5DEB8_2163B90C08AB4A18970A7F3ECE79DCFC_en_1_f71bd37d18d146c19e222e89fcffe278_3' type='hidden' value=" Home?="">
... instead of it rendering like this:
<li id="Home">...</li>
Now, that having been said, I can change my code to not use the CustomItemGenerator and it works fine in the browser and Page Editor as follows:
GenericContentPageItem navItem = (GenericContentPageItem)e.Item.DataItem;
Item nav = Sitecore.Context.Database.GetItem(navItem.ID);
liMenuItem.ID = nav.Fields["Nav Id"].ToString();
I would like to avoid having to hardcode field names in my code, which is why I am using CustomItemGenerator. Is there something that I'm doing wrong with my code that it doesn't want to work in Page Editor?
Thanks!
If you need the actual value out of the field regardless of if you are in the page editor or not, you want to use the Raw property:
liMenuItem.ID = navItem.NavId.Raw;
I am trying to create a custom list action for SharePoint (Office 365) and I need to get current list view. However if I add ribbon action I have some problems to find currently selected list view. My trials:
a) It would be the best to have some url tokent (like {View}) with current view ID, however it looks like such does not exist.
b) I had an idea to find selected view from the source url, however if I add Source={Source} parameter to the custom action, I get Source resolved to : Source=https://mysite.sharepoint.com/_layouts/15/commandui.ashx?ver=%2D1037522208&lcid=1033&qt=commandhandlers
(while I'd expect something like https://mysite.sharepoint.com/_layouts/15/start.aspx#/Lists/My%20List/AllItems.aspx?InitialTabId=Ribbon%2EList&VisibilityContext=WSSTabPersistence )
c) .. ?
Any ideas how to get currently selected list view?
it looks like there are more then one way to create custom action for every list. My way was just remove RegistrationType and RegistrationId:
<CustomAction
Id="65695319-4784-478e-8dcd-4e541cb1d682.CustomAction"
Location="CommandUI.Ribbon"
Sequence="10001"
Title="Invoke custom action">
Another way is to register custom action to content to content type 0x01:
<CustomAction
Id="65695319-4784-478e-8dcd-4e541cb1d682.CustomAction"
Location="CommandUI.Ribbon"
RegistrationType="ContentType"
RegistrationId="0x01"
Sequence="10001"
Title="Invoke custom action">
This way I get results as expected
Im am using Play 2.0.4 and
helper.options(myitems)
in my template (inside of a helper.select)
In this case, how can I define the default selected entry, which shall be one entry out of myitems? Thanks for any hint!
A little bit more about my case:
Imagine a news archive, showing all news titles. This news archive uses pagination, pagination uses GET to pass the next/previous page number.
The play framework however will only correctly select the currently selected "select" item (here: news category) when a POST request was used - while pagination uses GET!
Intended behaviour: While a filter is applied / a specific news category is selected, this shall always be visible to the user by preselecting the currently selected news category in the "select" form.
A "screenshot" for illustration:
So, anyone having a good idea on how to cope with this problem? Any way to tell Play manually which entry from the "select" form it shall select? '_default always adds a new entry instead of selecting one out of the given options ): Would be great, if one wouldn't have to build the complete "select" form manually.
Try passing '_default option to select helper:
#import views.html.helper._
#select(form("email"), options(List("first", "third")), '_default -> "second")
It seems, unfortunately, the only way to figure it out is to look up the source.
Update:
Specifying _default property doesn't set selected attribute on option tag. It looks like the only way to preselect entry is to pass prefilled form to the template. For example, suppose you have following form:
case class RegInfo(email: String, color: String)
private val registrationForm = Form(
mapping(
"email" → email,
"color" → nonEmptyText(minLength = 5, maxLength = 32)
)(RegInfo.apply)(RegInfo.unapply)
)
Then in the action prefill form before passing to the view:
def create = Action {
Ok(html.create(registrationForm.fill(RegInfo("user#qwe.com", "blue"))))
}
Then in template use helper:
#select(form("color"), options(List("red", "green", "blue")))
And value will be preselected.
Ended up with the pragmatic approach:
<select id="myfield" name="myfield" >
<option class="blank" value="">-- All items --</option>
#for((key, value) <- MyModel.options) {
#if(key == GETValuePassedToTemplate) {
<option value="#key" selected>#value</option>
} else {
<option value="#key">#value</option>
}
}
</select>
Still wondering if there is a better option / way to do it.
Actually, there is a nicer solution to it. If you call the template having the form partially bound you will achieve your goal. Here's the code for your controller:
Ok(views.html.myForm(myForm.bind(
Map("fieldName1" -> "value1",
"fieldName2" -> "value2"))))
Make sure you map fieldnames to the values of the options you want pre-selected.
Still wondering if there is a better option / way to do it.
Well, if your not hell-bent on using play to solve this particular problem, you could always solve it using JavaScript and jQuery:
$(function () {
$('#yourSelect_id').val(5);
}
Where your select options each has values and the one option you whish to pre select has value 5.