How to remove node id and extension from url in Umbraco - umbraco

right now I am working on a project, where I have to show a header navigation with url picker data type, for that I took two fields: Text(Text String) & Link(Url Picker).
To get this navigation link this I have done following code:
Default.aspx
<asp:Repeater ID="rptMainNavListing" runat="server" OnItemDataBound="rptMainNavListing_OnItemDataBound">
<HeaderTemplate>
<div class="header_top_links_right">
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink ID="hlLink" runat="server">
</asp:HyperLink>
<asp:Literal ID="ltText" runat="server"></asp:Literal>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</div>
</FooterTemplate>
</asp:Repeater>
Default.aspx.cs
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Reshape.Framework;
using Reshape.Framework.UI;
using Reshape.Framework.Constants;
using umbraco.NodeFactory;
namespace Reshape.UserControls {
public partial class Header : BaseLayout {
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
Node currentNode = Common.GetMainNavigationFolder();
var childList = currentNode.Children;
rptMainNavListing.DataSource = currentNode.Children;
rptMainNavListing.DataBind();
}
}
protected void rptMainNavListing_OnItemDataBound(object sender, RepeaterItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
Node itm = e.Item.DataItem as Node;
if (itm != null) {
Literal ltText = (Literal)e.Item.FindControl("ltText");
HyperLink hlLink = e.Item.FindControl("hlLink") as HyperLink;
if (ltText != null) {
ltText.Text = itm.GetProperty("text").Value;
}
if (hlLink != null) {
hlLink.NavigateUrl = itm.Url;
hlLink.Text = itm.GetProperty("link").Value;
}
}
}
}
}
}
After debugging this code I got url in following form(with id & extension)
False1154/regions.aspxRegions
here id =False1154
extension =regions.aspx
I want url only like "Regions".

In web.config, set the umbracoUseDirectoryUrls value to true.
There is some - rather outdated though - documentation here: http://our.umbraco.org/wiki/install-and-setup/setting-up-umbraco-for-friendly-urls

Change your code to following code....and you will get rid to this problem :-)
if (childList.Count > 0) {
rptMainNavListing.DataSource = childList; ;
rptMainNavListing.DataBind();
}
Repeater Code
protected void rptMainNavListing_OnItemDataBound(object sender, RepeaterItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
Node itm = e.Item.DataItem as Node;
if (itm != null) {
Literal ltText = (Literal)e.Item.FindControl("ltText");
HyperLink hlLink = e.Item.FindControl("hlLink") as HyperLink;
if (itm.GetProperty(FieldName.LINK) != null && !string.IsNullOrEmpty(itm.GetProperty(FieldName.LINK).Value)) {
hlLink.NavigateUrl = umbraco.library.NiceUrl(Convert.ToInt16(itm.GetProperty(FieldName.LINK).Value));
}
hlLink.Text = itm.GetProperty(FieldName.TEXT).Value;
}
}
}

Related

load more items in Listview from ViewModel in xamarin forms

How to load more items in Listview from ViewModel ?
Code Implemented :
listview.ItemAppearing += (sender, e) =>
{
if(isLoading || Items.Count == 0)
return;
//hit bottom!
if(e.Item.ToString() == Items[Items.Count - 1])
{
LoadItems();
}
};
in my xaml.cs
But need to do the same in my ViewModel...
try the following thing & let me know if you need some more help.
I used MessagingCenter to achieve it.
In your xaml.cs file add this
public partial class Results : ContentPage
{
public Results()
{
InitializeComponent();
NavigationPage.SetBackButtonTitle(this, "");
listview.ItemAppearing += (object s, ItemVisibilityEventArgs e) =>
{
MessagingCenter.Send(this, "Search:LastResultShown", e);
};
}
}
Now subscribe to your MessagingCenter in your ViewModel & remember to unsubscribe it as well.
public class ResultsVM : ViewModelBase
{
public ResultsVM() : base()
{
MessagingCenter.Subscribe<Results, ItemVisibilityEventArgs>(this, "Search:LastResultShown", OnItemAppearing);
}
public override void CleanupPage()
{
base.CleanupPage();
MessagingCenter.Unsubscribe<Results, ItemVisibilityEventArgs>(this, "Search:LastResultShown");
}
private async void OnItemAppearing(object sender, ItemVisibilityEventArgs e)
{
//Here will be your code
if ( ResultsList.Count == 0 || e == null || e.Item == null ) { return; }
var lastItem = ResultsList.ElementAtOrDefault(ResultsList.Count - 1);
if ( lastItem != null && e.Item == lastItem ) { LoadNextItems(); }
}
}
OnItemAppearing will hit everytime when your list comes at the end of screen.

button_Click event never hit

I have a web application utilizing master pages. For some reason, when I add a buttonclick event, the method is never hit. The page goes through the normal page_load events. How do I get my button click event to fire? Previously, This worked just fine, now this is happening in my whole application where the !page.IsPostBack always evaluates false from a button_Click
I have tried adding script Handlers and that doesnt seem to help
in the UI page:
<asp:Button ID="Button1" CssClass="btn btn-primary"
OnClick="putAccoutDetail" runat="server" Text="Save Changes" />
in the CodeBehind
protected void Page_Load(object sender, EventArgs e)
{
if (Session["Authenticated"] == null ||
Session["Authenticated"].ToString() != "true")
{
Response.Redirect("~/Login.aspx");
}
if (!Page.IsPostBack)
{
if (Session["UserID"] != null)
{
UserID = Convert.ToInt32(Session["UserID"]);
getUserData(UserID);
}
}
}
public void putAccoutDetail(object sender, EventArgs e)
{
string statusMsg = string.Empty;
var userInfo = db.UserMasts.FirstOrDefault(s => s.ID == UserID);
if (userInfo != null)
{
userInfo.UserName = txtUserName.Text;
userInfo.MilEmail = txtEmail.Text;
string base64 = Request.Form["imgCropped"];
if (base64.Length > 0)
{
byte[] bytes = Convert.FromBase64String(base64.Split(',')[1]);
String fileName = Guid.NewGuid().ToString() + ".png";
userInfo.PhotoPath = fileName;
ImagePhoto.ImageUrl = "/Images/Users/" + userInfo.PhotoPath;
using (FileStream stream = new FileStream(Server.MapPath("~/Images/Users/" + fileName), FileMode.Create))
{
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
}
}
try
{
dHelper.LogAction("Update User Detail : " + userInfo.UserName);
db.SubmitChanges();
statusMsg = "Successfully Updated";
lblstatusMsg.Text = statusMsg;
lblstatusMsg.Visible = true;
}
catch(Exception ex)
{
statusMsg = "Update Failed";
lblstatusMsg.Text = statusMsg;
lblstatusMsg.Visible = true;
}
}
The issue was that the form had unhandled ASP validators on certain fields. I added a validation group to those and then handled them in the button_Click and all is working

having trouble clearing textboxes

i want to clear all textboxes. wrote the public function as:
public void clean(Control parent)
{
try
{
foreach (Control c in parent.Controls)
{
TextBox tb = c as TextBox; //if the control is a textbox
if (tb != null)//Will be null if c is not a TextBox
{
tb.Text = String.Empty;//display nothing
}
}
}
catch (Exception ex)
{
Console.WriteLine("{0} Exception caught.", ex);
}
}
in the class of the page i want it to be called i declared:
PublicFunctions pubvar = new PublicFunctions();
and i call it as
pubvar.clean(Page);
but its not working... not even throwing an error... and my textboxes arent clearing... help?
You should use recursive loop to check all the controls.
try this code
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
public class PublicFunctions
{
public void Clean(Control parent)
{
var controls = GetAllControls(parent);
foreach (Control c in controls)
{
TextBox tb = c as TextBox;
if (tb != null)
{
tb.Text = String.Empty;
}
}
}
public IEnumerable<Control> GetAllControls(Control parent)
{
foreach (Control control in parent.Controls)
{
yield return control;
foreach (Control innerControl in control.Controls)
{
yield return innerControl;
}
}
}
}

How to add images in validation summary along with the error message?

I wanna display error message with success image(green tick mark) and failure image(Red warning) in validation summary. how to do this.
and i validation summary i will have to display some text in bold, italics etc. for that i tried to pass string like this.
inValid <b>username</b> or <b>password</b>
But in the page its rendering as it is. it is not showing username and password in bold. is there any way to do that. I am getting this validation error messages in controller and adding this to ModelState.add(error);
The ValidationSummary helper HTML encodes by default all messages. You could write a custom helper which doesn't HTML encode:
public static class HtmlExtensions
{
public static MvcHtmlString MyValidationSummary(this HtmlHelper htmlHelper, bool excludePropertyErrors, string message)
{
var formContext = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
if (formContext == null && htmlHelper.ViewData.ModelState.IsValid)
{
return null;
}
string messageSpan;
if (!string.IsNullOrEmpty(message))
{
TagBuilder spanTag = new TagBuilder("span");
spanTag.InnerHtml = message;
messageSpan = spanTag.ToString(TagRenderMode.Normal) + Environment.NewLine;
}
else
{
messageSpan = null;
}
var htmlSummary = new StringBuilder();
var unorderedList = new TagBuilder("ul");
IEnumerable<ModelState> modelStates = null;
if (excludePropertyErrors)
{
ModelState ms;
htmlHelper.ViewData.ModelState.TryGetValue(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix, out ms);
if (ms != null)
{
modelStates = new ModelState[] { ms };
}
}
else
{
modelStates = htmlHelper.ViewData.ModelState.Values;
}
if (modelStates != null)
{
foreach (ModelState modelState in modelStates)
{
foreach (ModelError modelError in modelState.Errors)
{
var errorText = modelError.ErrorMessage;
if (!String.IsNullOrEmpty(errorText))
{
var listItem = new TagBuilder("li");
listItem.InnerHtml = errorText;
htmlSummary.AppendLine(listItem.ToString(TagRenderMode.Normal));
}
}
}
}
if (htmlSummary.Length == 0)
{
htmlSummary.AppendLine(#"<li style=""display:none""></li>");
}
unorderedList.InnerHtml = htmlSummary.ToString();
var divBuilder = new TagBuilder("div");
divBuilder.AddCssClass((htmlHelper.ViewData.ModelState.IsValid) ? HtmlHelper.ValidationSummaryValidCssClassName : HtmlHelper.ValidationSummaryCssClassName);
divBuilder.InnerHtml = messageSpan + unorderedList.ToString(TagRenderMode.Normal);
if (formContext != null)
{
// client val summaries need an ID
divBuilder.GenerateId("validationSummary");
formContext.ValidationSummaryId = divBuilder.Attributes["id"];
formContext.ReplaceValidationSummary = !excludePropertyErrors;
}
return MvcHtmlString.Create(divBuilder.ToString(TagRenderMode.Normal));
}
}
Now you have the possibility to use HTML tags in your validation messages:
ModelState.AddModelError("user", "invalid <b>username</b> or <b>password</b>");
and then:
<%= Html.MyValidationSummary(true, null) %>
Obviously by doing this you should ensure that your error messages contain valid HTML structure.
There is no doubt that #Darin Dimitrov answer is the best practice. but as a newbie i am gaining that functionaliy by using ViewBag
Inside Controller
if(true) //All is well and success msg is to be sent
{
ViewBag.Errors = null;
ViewBag.Success = "<b>Login</b> is Successful";
//Redirect
}
else
{
ViewBag.Errors = "<b>Some Error messages</b>";
ViewBag.Success = null;
}
Inside View()
#if(ViewBag.Errors != null)
{
<div class="error">#Html.Raw(#ViewBag.Errors)</div>
}
#if(ViewBag.Success != null)
{
<div class="success">#Html.Raw(#ViewBag.Success)</div>
}
Now the Css
.error { color: red; background-image:error_image.png; }
.success { color:green; background-image : success_image.png; }

Copy ModelState Errors to TempData & Display them In the view

Most of my action methods return PartialViews on success and RedirectToAction results on failure. For that, I would like to copy the model state errors into TempData so I could display them to the user. I've read several questions here on SO and some external links but none of them worked for me... I'm decorating the ActionMethod with ModelStateToTempData attribute from MvcContrib, then displaying it as follows in the view: (this is just a prototype)
#if (TempData.Count > 0)
{
foreach (var obj in TempData)
{
var errors = ((ModelStateDictionary)obj.Value).Values;
foreach (var error in errors)
{
<div style="position:absolute; background:Black; color:White; top:250px; left:550px;">
<span style="margin-bottom:5px; display:block; height:25px;">#error.Value</span>
</div>
}
}
}
Rather than displaying the error itself, I keep getting System.Web.Mvc.ValueProviderResult. I know this is all wrong, and eventually I would want to filter the model state errors into a dictionary inside the TempData but for now I just want to have the error string displayed in the view.
P.S: I've tried to do it manually without the MvcContrib attribute, and I got the same result. But I do prefer to use my own code so I could have more control over the whole issue.
Any suggestions?
Ok After trying a million things, I found the answer myself... :)
if (TempData["ModelErrors"] == null)
TempData.Add("ModelErrors", new List<string>());
foreach (var obj in ModelState.Values)
{
foreach (var error in obj.Errors)
{
if(!string.IsNullOrEmpty(error.ErrorMessage))
((List<string>)TempData["ModelErrors"]).Add(error.ErrorMessage);
}
}
return RedirectToAction("Index", "Home");
And in the view:
<div id="validationMessages">
#{
var errors = (List<string>)TempData["ModelErrors"];
}
#if (errors != null && errors.Count() > 0)
{
<div style="position:absolute; background:Black; color:White; top:250px; left:550px;">
#foreach (var error in errors)
{
<span style="margin-bottom:5px; display:block; height:25px;">#error</span>
}
</div>
}
</div>
UPDATE:
Here it is inside an ActionFilter:
public class CopyModelStateErrorsToTempData : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Only export when ModelState is not valid
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
//Export if we are redirecting
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
if (filterContext.Controller.TempData["ModelErrors"] == null)
filterContext.Controller.TempData.Add("ModelErrors", new List<string>());
foreach (var obj in filterContext.Controller.ViewData.ModelState.Values)
{
foreach (var error in obj.Errors)
{
if (!string.IsNullOrEmpty(error.ErrorMessage))
((List<string>)filterContext.Controller.TempData["ModelErrors"]).Add(error.ErrorMessage);
}
}
}
}
base.OnActionExecuted(filterContext);
}
}
I started going down this road, and then read your answer. I combined them into the following files:
TempDataDictionaryExtensions.cs
I created extension methods to do the dirty work on the TempData, because I felt it didn't belong in the Action Filter itself.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace Project.Web.UI.Domain
{
public static class TempDataDictionaryExtensions
{
private const string _ModelStateErrorsKey = "ModelStateErrors";
public static IEnumerable<string> GetModelErrors(this TempDataDictionary instance)
{
return TempDataDictionaryExtensions.GetErrorsFromTempData(instance);
}
public static void AddModelError(this TempDataDictionary instance, string error)
{
TempDataDictionaryExtensions.AddModelErrors(instance, new List<string>() { error });
}
public static void AddModelErrors(this TempDataDictionary instance, IEnumerable<string> errors)
{
TempDataDictionaryExtensions.AddErrorsToTempData(instance, errors);
}
private static List<string> GetErrorsFromTempData(TempDataDictionary instance)
{
object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey);
if (tempObject == null)
{
return new List<String>();
}
List<string> tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>;
if (tempErrors == null)
{
return new List<String>();
}
return tempErrors;
}
private static void AddErrorsToTempData(TempDataDictionary instance, IEnumerable<string> errors)
{
List<string> tempErrors;
object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey);
if (tempObject == null)
{
tempErrors = new List<String>();
}
else
{
tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>;
if (tempErrors == null)
{
tempErrors = new List<String>();
}
}
tempErrors.AddRange(errors);
instance[TempDataDictionaryExtensions._ModelStateErrorsKey] = tempErrors;
}
}
}
TempDataModelStateAttribute.cs
My original, copied the errors out of TempData back into ModelState prior to the ActionResult executing via OnResultExecuting. This is a combination of copying them into TempData and back out.
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace Project.Web.UI.Domain
{
public class TempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
IEnumerable<string> modelErrors = ((Controller)filterContext.Controller).TempData.GetModelErrors();
if (modelErrors != null
&& modelErrors.Count() > 0)
{
modelErrors.ToList()
.ForEach(x => ((Controller)filterContext.Controller).ModelState.AddModelError("GenericError", x));
}
base.OnResultExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
if (filterContext.Result is RedirectResult
|| filterContext.Result is RedirectToRouteResult)
{
List<string> errors = new List<string>();
foreach (var obj in filterContext.Controller.ViewData.ModelState.Values)
{
foreach (var error in obj.Errors)
{
errors.Add(error.ErrorMessage);
}
}
((Controller)filterContext.Controller).TempData.AddModelErrors(errors);
}
}
base.OnActionExecuted(filterContext);
}
}
}
You should seriously consider this concept:
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg

Resources