How to combine Blazor Component Modal Prompts so I only need to have one for all validations - components

I have defined a blazor component that handles error prompts. If I need to display an error prompt I do the following.
#if (NoCharacterName)
{
<PromptModalComponent OnModalChange="NoCharacterName_Response"
messageTitle="Warning!"
message="Please enter a name for your character"
Type="warning"
ConfirmButtonText="Continue"
NoCancelButton="True"
#ref="#modalPrompt"></PromptModalComponent>
}
#if (NoSexSelected)
{
<PromptModalComponent OnModalChange="NoSexSelected_Response"
messageTitle="Warning!"
message="Please select a sex for your character"
Type="warning"
ConfirmButtonText="Continue"
NoCancelButton="True"
#ref="#modalPrompt"></PromptModalComponent>
}
#if (NoBookInUse)
{
<PromptModalComponent OnModalChange="NoBookInUse_Response"
messageTitle="Warning!"
message="Please Select a book to use"
Type="warning"
ConfirmButtonText="Continue"
NoCancelButton="True"
#ref="#modalPrompt"></PromptModalComponent>
}
Can this be done and I only have one of the modal components listed? Therefore I can update the message, messageTitle, and other parameters without having to have a component for each possible warning?

Use a List<T> and create a foreach where you render each modal.
Example:
#foreach (var validationError in ValidationErrors)
{
<PromptModalComponent OnModalChange="#validationError.OnChangeEvent"
messageTitle="#validationError.Title"
message="#validationError.Message"
Type="#validationError.Type"
ConfirmButtonText="#validationError.ConfirmButtonText"
NoCancelButton="#validationError.HasCancel" />
}
Can't give an example of #ref="#modalPrompt", because I do not know how this object is used.
Although, my opinion this is not user friendly. I would create one modal to list all validation errors, which also simplifies your code. But only if modals are some requirement.
But if it is not required, use DataAnnotations and EditContext with the EditForm component containing DataAnnotationsValidator and ValidationSummary or ValidationMessage components and show these validation errors as the user edits the form.
You can also create custom validation using DataAnnotations and EditContext.
On top of this you can also create custom attributes inheriting the ValidationAttribute class to further automate your validation needs.

Related

create setup form for custom module

I have a custom module getting executed right after the PDFGenerator finished. I followed this guide on how to create a custom module
https://stackoverflow.com/a/55799101/9945420
When processing a batch document I want to manipulate the generated PDF file and add a footer to that file. The content of that footer needs to get configured in the Administration module.
So within my project called "StampOnScanProcess" I added a Folder called "Setup" with two files. A Form called "FrmSetup"
public partial class FrmSetup : Form
{
private IBatchClass batchClass;
public FrmSetup()
{
InitializeComponent();
}
public DialogResult ShowDialog(IBatchClass batchClass)
{
this.batchClass = batchClass;
// Load previous Settings ...
return this.ShowDialog();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
// Save ...
this.Close();
}
}
and a UserControl called "UserCtrlSetup"
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISetupForm
{
[DispId(1)]
AdminApplication Application { set; }
[DispId(2)]
void ActionEvent(int EventNumber, object Argument, out int Cancel);
}
[ClassInterface(ClassInterfaceType.None)]
[ProgId(CUSTOM_MODULE_NAME_SETUP)]
public partial class UserCtrlSetup : UserControl, ISetupForm
{
private const string CUSTOM_MODULE_NAME_SETUP = "StampOnScanProcess.Setup";
private AdminApplication adminApplication;
public AdminApplication Application
{
set
{
value.AddMenu(CUSTOM_MODULE_NAME_SETUP, CUSTOM_MODULE_NAME_SETUP, "BatchClass");
adminApplication = value;
}
}
public void ActionEvent(int EventNumber, object Argument, out int Cancel)
{
Cancel = 0;
if ((KfxOcxEvent)EventNumber == KfxOcxEvent.KfxOcxEventMenuClicked && (string)Argument == CUSTOM_MODULE_NAME_SETUP)
{
FrmSetup form = new FrmSetup();
form.ShowDialog(adminApplication.ActiveBatchClass);
}
}
}
I modified my registration file and added the setup form to it
[Modules]
StampOnScanProcess
[StampOnScanProcess]
RuntimeProgram=StampOnScanProcess.exe
ModuleID=StampOnScanProcess.exe
Description=...
Version=10.2
SupportsNonImageFiles=True
SupportsTableFields=True
SetupProgram=StampOnScanProcess.Setup
[Setup Programs]
StampOnScanProcess.Setup
[StampOnScanProcess.Setup]
Visible=0
OCXFile=StampOnScanProcess.exe
ProgID=StampOnScanProcess.Setup
When launching the Administration module I head over to the Batch Class Properties => Queues and want to call this setup form by clicking the Properties button in the middle.
Unfortunately the properties button is disabled so I can't open the setup form. This form gets added to the context menu of the batch class
How can I bind this form to the properties button instead? And what is the best way to store configured data and access it when the runtime application gets executed?
I need to think about how to store data because some users have user profiles
and the runtime application currently logs in with no credentials.
public void LoginToRuntimeSession()
{
login = new Login();
login.EnableSecurityBoost = true;
login.Login();
login.ApplicationName = CUSTOM_MODULE_ID;
login.Version = "1.0";
login.ValidateUser($"{CUSTOM_MODULE_ID}.exe", false, "", "");
session = login.RuntimeSession;
}
So it might happen that I have to store the credentials on setup too.
How can I bind this form to the properties button instead?
All interactions with menu entries are handled by ISetupForm.ActionEvent. New entries are added with the AddMenu method of the AdminApplication object. Kofax differentiates between multiple entries by name - imagine that you could have multiple menu entries at the same time, one on batch class level, another one on document class level, and another one in the ribbon - just to name a few examples. Kofax uses the same approach in any component that integrates into Administration (e.g. Custom Modules or Workflow Agents).
This is an example from one of our components. Note that three entries are added on BatchClass level and two more on DocumentClass level.
value.AddMenu("BatchClass.GeneralConfig", "Field Panel - General Configuration", "BatchClass");
value.AddMenu("BatchClass.FieldEditor", "Field Panel - Configure Batch Fields", "BatchClass");
value.AddMenu("DocumentClass.FieldEditor", "Field Panel - Configure Index Fields", "DocumentClass");
value.AddMenu("CopyBatchFieldConfig", "Field Panel - Copy Batch Field Configuration", "BatchClass");
value.AddMenu("PasteBatchFieldConfig", "Field Panel - Paste Batch Field Configuration", "BatchClass");
value.AddMenu("CopyIndexFieldConfig", "Field Panel - Copy Index Field Configuration", "DocumentClass");
value.AddMenu("PasteIndexFieldConfig", "Field Panel - Paste Index Field Configuration", "DocumentClass");
Each entry is no identified by its event text, the first parameter. For example, BatchClass.GeneralConfig is intended to open up a generic configuration dialog - on batch class level.
Now, back to our ActionEvent - this is how I distinguish between the entry selected by the user:
if ((KfxOcxEvent)EventNumber == KfxOcxEvent.KfxOcxEventMenuClicked)
{
AdminForm form = new AdminForm();
switch ((string)Argument)
{
case "BatchClass.GeneralConfig":
ConfigureGeneral(kcApp.ActiveBatchClass);
break;
[I] want to call this setup form by clicking the Properties button in
the middle.
I don't know if you can use this button - I would assume yes - yet personally I tend to put settings either on batch or document class level. For example - your PDF annotation settings may different from document class to class - having an entry on this level seems more natural.
And what is the best way to store configured data and access it when
the runtime application gets executed?
Custom Storage Strings, and you can let your imagination run wild here. The most simplistic approach is to store key-value pairs during setup, and retrieve them in runtime. Here's a generic call (BatchClass is an IBatchClass object, i.e. a pointer to the ActiveBatchClass property of the AdminApplication object):
// set a CSS
BatchClass.set_CustomStorageString(name, value);
// get a CSS
BatchClass.get_CustomStorageString(name)
I usually use a single custom storage string only and store custom object - the object is a base64-encoded serialized XML using XmlSerializer - but again, that's up to you. The only recommendation is to rely on CSS only - don't use external files to store configuration parameters. A CSS is an integral part of your batch class - so, when exporting said class and importing it on a different system, your entire configuration will be there.
I need to think about how to store data because some users have user
profiles
Usually, you don't need to worry about that. The properties for user and password in ValidateUser are entirely optional - and since you're planning to write an unattended module - ideally a Windows Service, credentials should be maintained there. Kofax and Windows would automatically make sure the credentials are passed on, and your module will run under this user's context. Just make sure the user has permissions for the module and all associated batch classes. It's different if you're planning to write an attended module, for example an enhanced Validation module.

Load data in custom form by using Kentico 9

I searched the whole web and I couldn't found any good topic which expose the proper way to do it.
I have a very simple web which I developed using Kentico 9 CMS. This web only contains two subpages and a header to navigate between those.
The "Home" subpage contains a custom form which remains connected to a SQL table which is populated every time you press submit with certain data.
On the other hand, the other page, shows the stored data by using a custom web part which connects to the DB by using BizFormItemProvider and this object is used as a layer to binding the data in a control.
Now is my point. If you see, there is a button to "Edit" a certain row and my intention is to Redirect to "Home" (which contains the form) and sending via QueryString the ID of the row attempted to edit.
I was unable to understand how can you re-fill the form with its data using an ID.
Maybe because I never worked with a CMS before, I'm looking the development such as pure ASP.NET and it could not be the correct one.
Custom
Given that your solution uses a custom form for entering the data, as well as a custom web part for listing the stored data, you will need to use a custom solution to handle the editing of data, as well.
In the custom webpart on the Home page, in a load event, you can retrieve the form data and set the values on the form controls.
protected void Page_Load(object sender, EventArgs e)
{
// Ensure that the form is not being posted back,
// to prevent entered data from being overwritten
if(!IsPostBack)
{
// Get the form item ID from the query string
var personId = QueryHelper.GetInteger("personId", 0);
if(personId > 0)
{
// Get the biz form item, and set form control values
var bizFormItem = BizFormItemProvider.GetItem(personId, "customFormClassName");
txtFirstName.Text = bizFormItem.GetStringValue("FirstName", string.Empty);
}
}
}
Similarly, when Submit is clicked, you can update the existing form item with the new data
protected void btnSubmit_OnClick(object sender, EventArgs e)
{
// Get the form item ID from the query string
var personId = QueryHelper.GetInteger("personId", 0);
if(personId > 0)
{
// Retrieve the existing biz form item,
// and update it from the form control values
var bizFormItem = BizFormItemProvider.GetItem(personId, "customFormClassName");
bizFormItem.SetValue("FirstName", txtFirstName.Text);
bizFormItem.Update();
}
else
{
// Your code for inserting a new form item...
}
}
The Kentico way
You should really consider using the Kentico form engine for accomplishing this task. Instead of using a custom form for entering the data, use the built-in On-line form webpart.
The benefits are numerous, such as:
Ability to set the form layout through the CMS, and use alternative layouts
Automatic confirmation email to the submitter of the form, as well as notification emails to the administrators
To accomplish your task, you can customise the On-line form webpart to support loading of existing data.
In the bizform.ascx.cs file, add code to the SetupControl method:
protected void SetupControl()
{
if (StopProcessing)
{
// Existing code...
}
else
{
// Existing code...
// Get the form item ID from the query string
var personId = QueryHelper.GetInteger("personId", 0);
if(personId > 0)
{
// Get the biz form item, and set form control values
var bizFormItem = BizFormItemProvider.GetItem(personId, "customFormClassName");
if(bizFormItem != null)
{
// Set the item ID
viewBiz.ItemID = bizFormItem.ItemID;
}
}
}
}
This will automagically switch the form to Edit mode, instead of Insert mode, as soon as you set the ItemID property. Clicking the Submit button will save changes on the existing form item.
You will not need to worry about validation in your code, and inserting data will still work.
Is this a contact form that you are using Kenticos built in form application for, or is it a custom form? If it is a custom form you can create a transformation with a link that will contain the ID. If it is a biz form, you can still create a transformation in Page Types (create a new page type and select "The page type is only a container without custom fields"), then write a custom query to get the biz form data, and use a repeater to display the data with that transformation.

How to add button + to subgrid of hierarchical relation?

I have a hierarchical relation inside an entity X, I Have parent lookup which allow to give parent to a record of this entity, and I have created a Subgrid attached to this lookup within the same form of the entity:
The problem is that the display of the button + is unstable in this subgrid, sometimes it appears sometimes no. I dont know if this problem is related to some setting or it is a bug of dynamics crm online last version?
For information, I don't have this problem with other sub-grids.
Thanks in advance,
if you want to add a custom button you may do this as follows
function CreateButton() {
var connectionSubGridPlusBtn = document.getElementById("Connections_addImageButton").parentNode.parentNode;
//Connections_addImageButton is the id of + button
if (connectionSubGridPlusBtn != null) {
//New Button
var div = document.createElement("div");
div.className = "ms-crm-contextButton";
div.innerHTML = "<button id='newButton' type='button' style='width:80px;cursor: pointer;padding:0px' >New Button</button>";
connectionSubGridPlusBtn.appendChild(addVendorDiv);
//Event and url for new
document.getElementById("newButton").onclick = function () {
//Write codefor the button click event
}
}
}
call this function on load of the form
The entity has to be created before you're able to add related entities. You can add disable all required fields, and perform a save in the onload, and you should always see the plus sign.
A slightly better solution is to override the create button for the entity, and rather than directing to the create form, perform a rest entity creation, then direct to that form. Then you don't have to perform a save in the on load.

How to create layout elements in Orchard 1.9

Can someone please guide me on how to create layout elements in Orchard 1.9. I couldn't find any resource online.
In general, creating a new layout element is similar to creating a new part. There is a driver and a few views involved in the process. To the point - you need to implement as follows:
An element class.. Class that inherits from Element, which contains all the element data. A model, so to speak.
A driver. Class that inherits from ElementDriver<TElement>, where TElement is the type you created above. Each element has it's own driver that handles displaying admin editor (and the postback) and frontend display views.
Shapes. All shapes should be placed under /Views/Elements/ folder, by convention.
Display shape. Named after your element, ie. MyElement.cshtml. This one renders your element on frontend.
Design display shape.. Named after your element, with .Design suffix, ie. MyElement.Design.cshtml. This one renders your element inside the layout editor.
Editor shape.. This one should be put in /Views/EditorTemplates/ folder instead. Default naming convention is Elements.MyElement.cshtml. It renders the editor shown when you drop a new element on layout editor canvas.
With all above done, your new element should appear in the list of elements on the right side of the layout editor, ready to use.
If you want to do some more complex elements, please check the existing implementations. Layouts module has a very decent architecture so you should get up to speed pretty quickly. Just keep in mind the necessary steps I wrote above.
To create a custom layout element first create a class that inherits from Element. Element is found in the Orchard.Layouts namespace so you need to add a reference. To follow Orchard standards put this file in a folder called Elements.
public class MyElement : Element
{
public override string Category
{
get { return "Content"; }
}
public string MyCustomProperty
{
get { return this.Retrieve(x => x.MyCustomProperty); }
set { this.Store(x => x.MyCustomProperty, value); }
}
}
Next, create a driver class in a folder called Drivers. This class inherits from ElementDriver<TElement> and likely you will want to override the OnBuildEditor and OnDisplaying methods. OnBuildEditor is used for handling creating our editors shape and updating our database when the editor is saved. OnDisplaying is used when we need to do things when displaying our element. Oftentimes, you will want to add properties to the shape which can be done with context.ElementShape.MyAdditionalProperty = "My Value";
public class MyElementDriver : ElementDriver<MyElement>
{
protected override EditorResult OnBuildEditor(MyElement element, ElementEditorContext context)
{
var viewModel = new MyElementEditorViewModel
{
MyCustomProperty = element.MyCustomProperty
};
var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.MyElement", Model: viewModel);
if (context.Updater != null)
{
context.Updater.TryUpdateModel(viewModel, context.Prefix, null, null);
element.MyCustomProperty = viewModel.MyCustomProperty;
}
return Editor(context, editor);
}
protected override void OnDisplaying(Reddit element, ElementDisplayContext context)
{
context.ElementShape.MyAdditionalProperty = "My Value";
}
}
We then just need our views. Our editor view goes into Views/EditorTemplates. The file name needs to be what we set the template name of the editor shape. In our case the view name will be Elements.MyElement.cshtml.
#model MyNameSpace.ViewModels.MyElementEditorViewModel
<fieldset>
<div>
#Html.LabelFor(m => m.MyCustomProperty, T("My Custom Property"))
#Html.TextBoxFor(m => m.MyCustomProperty, new { #class = "text medium" })
</div>
</fieldset>
Finally, we just need a view for our frontend. This view goes into the following folder Views/Elements. The name of the view file is the same as our element class name. For this example the file would be called MyElement.cshtml.
#using MyNameSpace.Elements
#using MyNameSpace.Models
#{
var element = (MyElement)Model.Element;
}
<h1>#element.MyCustomProperty</h1>
You will then have a new element that you can drag into your layout with the layout editor.
For more details on creating an element from start to finish check out my blog post on creating a Reddit element.

Sharepoint web part form validation blocks updating web part settings

I have written a web part in C# for Sharepoint 2007 which has a single field which is validated as a required field using RequiredFieldValidator(). The web part also has some configuration fields (ones you edit by clicking on Modify Shared Web Part).
When I make changes to these fields and try to apply them, the validation of the user field kicks in and prevents the update, even though I am not submitting the form. I am only trying to submit the settings. The web part may be used in a few places on our farm, so site collection administrators need to be able to change the settings - at the moment it is not friendly enough for these users to do so.
Here is where I validate the user field:
// Validate form field - required field, and max length is 100 characters.
InputFormRequiredFieldValidator messageRequiredValidator = new InputFormRequiredFieldValidator();
messageRequiredValidator.ControlToValidate = txtMessage.ID;
messageRequiredValidator.ErrorMessage = "You must write a message to send!";
messageRequiredValidator.Display = ValidatorDisplay.Dynamic;
messageRequiredValidator.Text = "<img src=\"/_layouts/images/CNSCA16.gif\"/> You must write a message to send.";
tc.Controls.Add(messageRequiredValidator);
Here is where I define one of the configuration fields:
private string recipientEmailAddress = "sender#domain.tld";
[WebBrowsable(true),
Personalizable(true),
WebPartStorage(Storage.Shared),
WebDescription("Email address the form should be sent to"),
WebDisplayName("Recipient Email Address"),
SPWebCategoryName("Email Settings")]
public string RecipientEmailAddress
{
get { return recipientEmailAddress; }
set { recipientEmailAddress = value; }
}
This is the first web part I have written, so there may be some subtleties I am missing in how to do admin configuration and validation of user submitted fields.
Ok - I've found the key to this. You can add a validationGroup property to each validator, and to the button that causes the validation. So I changed my code to include:
messageRequiredValidator.validationGroup = "UserInput";
and a similar property to my submit button. Now when I click on Ok in the ToolPane, it doesn't validate the UserInput validation group. That only happens when I click on my Submit button.
You can dynamically disable validations on OK, Cancel buttons in ApplyChanges method:
ToolPane pane = Zone as ToolPane;
if (pane != null)
pane.Cancel.CausesValidation = false;
OR you can also check if editor pane is open and disable validation in webpart :
WebPartManager wpm = WebPartManager.GetCurrentWebPartManager(Page);
if (wpm.DisplayMode == WebPartManager.EditDisplayMode)
{
//Page is in edit mode
}
I would suggest to use the SharePoint validation control.

Resources