I have an application in MVC5/C#
My index view is a simple list from a model. I added an additional html actionlink to view the history of any selected item. With this link, I am going to a different controller (ICS_HistoryView) and passing an id parameter.
Originally it broke because some of the items (Old_ItemID field) have / in them, causing the link to break. So, after some research, I learned that I can use Replace to replace / with -, so the url will not break and then switch it back in the controller of the new view. However, I am getting a null error when the view loads, on this line
#Html.ActionLink("History", "History", "ICS_HistoryView", new { id = item.Old_ItemID.Replace('/', '-')}, null)
But, without the Replace, it loads properly. Only when I click the History link, does the url break with the / in the parameter.
#Html.ActionLink("History", "History", "ICS_HistoryView", new { id = item.Old_ItemID}, null)
Can someone help me understand why it becomes null when I use replace and breaks the code?
I can provide the controller code if needed, but it's really simple. This is just a list view.
Example:
Old_ItemID = VNC/2/1
Without the Replace, I get the correct url with parameter VNC/2/1 but I get page not found, obviousl
Adding Replace, I get a null error - and I don't understand why
The only reason I suspect for this error is when item.Old_ItemID is null.
Otherwise it works fine for string with any value including empty string.
Could you try adding null-condition operator like item.Old_ItemID?.Replace("/","-")
For best practice, I would suggest such manipulations in Model/Domain classes.
Create a Get property or a method in Item (or whatever class that is) to replace tokens in URL.
i.e.
public string OldItemIdForUrlGeneration => this.Old_ItemID.Replace("/", "-");
and then
#Html.ActionLink("History", "History", "ICS_HistoryView", new { id = item.OldItemIdForUrlGeneration }, null)
Related
Currently I have a view that has just a single form with three values. When a user submits the form with those three values, my controller checks if all three values actually have a value other than being empty, and if they do then it calls my service that fetches data.
public IActionResult Index(string clientName = "", string tableName = "", string date = "")
{
if (!string.IsNullOrEmpty(clientName) && !string.IsNullOrEmpty(tableName) && !string.IsNullOrEmpty(date))
{
// Unimportant stuff for setting temp variables for FetchData parameters removed
TheData = _fieldDataService.FetchData(tempAcr, tempID, tableName, date, numRows);
}
return View(TheData);
}
My goal is to make the view display a loading icon or something while the data is being fetched. I've looked into JQuery and Ajax but I have no experience with either and cannot figure out how to apply them to my specific task. Since I am using Asp.Net Core, I also looked into using Blazor, but I couldn't wrap my head around it either.
Could somebody point me in the right direction as to what I should/could use to solve this problem? I have a vague understanding that there needs to be some sort of asynchronous function that retrieves the data, but nothing more than that.
You need to fetch the data with JavaScript and manipulate the UI to show a loader. But anyway, a request like this should be so fast, that you don't even need a loader.
I'm also a bit worried that you are passing a tableName as input parameter. You aren't just string concatenating the query right? You might be susceptible to SQL injections, see https://en.wikipedia.org/wiki/SQL_injection.
To do a request with JavaScript, look into the XMLHttpRequest, see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest, or the new way of doing it with fetch(...), see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch.
This answer shows a more practical example: Display loading image while ajax fetches file content.
I want to know, what's the best way to create a custom back button with parameters?
My example:
I have 4 pages that depend on each other and in these pages I have some actions like updating, deleting, creating and after these actions I need to go back on the last page I was before I am
So I have an ID, which I set on the first page and I have this same ID as the parameter for each page.
If I use the back button of the browser, I will have 2 problems .. 1- If I use it after an action, the browser will redirect to the same page as I am and the second time I click this button it will redirect me to the last page .. 2- will redirect me but no parameters.
And I have an obstacle, I have to clear the URL, so after all '?' I have to clean it, so I use this function:
function cleanUrl() {
urlpg = $(location).attr('href');
urllimpa = urlpg.split("?")[0]
window.history.replaceState(null, null, urllimpa);
setInterval("window.status = ''", 1);
}
Currently, I have this: #Html.ActionLink("","","",new { my parameters })
And this parameters I have an object like:
ObjPreviousPage
{
ID
Filter
Search
}
So, on all of my pages i have this:
#Html.ActionLink("","","", new { ID = x, Filter = "y", Search = "z" })
So I want to know, if have a way to better this or if this way isnt recommended
instead trying to find a hack to do this. I suggest you to rethink your concept how and when is someone redirected to a new URL.
So this could be also helpful to understand the basics
I'm trying to get a list of IwebElements that contain the attribute aria-required. Reason why I'm trying to get this list, is so that i can check if all required fields are necessary for the user to fill out, before he can continue to the next page.
So far after 2 days of searching I'm still convinced that it shouldn't be that hard. I'm using the expression:
".//*[#aria-required='true']"
From my research that would mean that it will search for ALL the elements starting from the root of my webdriver.
[TestMethod]
public void CreateProjectWithoutRequiredFields()
{
GoToProjectPage();
tracking = CM.GoToNewlyCreatedFrameAfterClickButton("ftbNew", tracking, theDriver);
CM.Wait(2000);
bool succesSave = false;
CM.LogToFile("Create project whitout required fields", tracking);
foreach (IWebElement e in theDriver.FindElements(By.XPath(".//*[#aria-required='true']")))
{
FillDataInNewProjectPage();
e.Clear();
CM.GetDynamicElementById("btnSave", theDriver).Click();
try
{
CM.GetDynamicElementById("titel", theDriver).Click();
}
catch (Exception)
{
succesSave = true;
NUnit.Framework.Assert.IsFalse(succesSave, "The page is saved with succes, without entering text in the following required fields : " + e.GetAttribute("id").ToString());
}
CM.Wait(1000);
}
}
I will try to explain what i did here:
First i went to a overview page with all my existing projects. On this page i clicked the ftbNew button to create a new project. The driver is automatically switch to the correct frame (i now the right frame is selected because i used this line on other page's.)
then the line
foreach (IWebElement e in theDriver.FindElements(By.XPath(".//*[#aria-required='true']")))
{
should normaly find a the elements in my driver with an attribute "aria-required='true'"
Then it would fill in the page with data, clear the first element that is found from its data en try to save it.
if the element titel is found on the page, than we are still on the same page en the save action wasn't successful ( <- so this is good)
so next we again overwrite every field on the page and clear this time the second element that is found.
en so on...
What I'm guessing, that xpath has difficulty finding the 'old' aria-required attribute... When i try to validate my expression using firebug and other xpath checkers, the aria-required attribute isn't always present. Sometimes it finds the input field sometimes it doesn't.
source code page
As you can see in the firebug console not all attributes are loaded, account-manager has a aria-required attribute, but project leader doesn't. If i inspect the element again, but this time click project leader. The attribute will be loaded. Very strange....
Extra info: I am using frame's and i know a lot can go wrong if you are situated in the wrong frame, but i am sure that he is looking in the correct frame. Especially because i can't find the elements using firebug with the above expression. If i change my expression to .//input, it will find the elements but also selects input fields that aren't required.
In advance i want to thank everybody that want to look into my problem :)
Adriaan
Based on your description of the behavior on the page, you cannot rely on the aria-required attribute to indicate a required field. I think that you should go back to the developers of the site to ask them to give you a reliable handle. It may be as simple as looking for the "*" as the last character of the label associated with the input field, but that's kind of annoying to have to deal with.
As an aside, you should consider catching a more specific exception for your success case. Right now, if ANY exception happens, you'll declare success, but that may not be what you really want to do.
I would like to amend data before it reaches my controller.
We've altered model binders etc through the solution and so amending those isn't an option for me at this time - I'd like to know however if its possible to amend the value being entered before it hits the controller:
Razor code (inside a foreach):
#Html.EditorFor(x=>x.Value);
I've tried things like .Replace(...) but doesn't allow me to amend it that way.
I appreciate what best practice is but time being involved I would like the quick solution and change for the right solution later... Im sure everyone can appreciate that one!
Controller code: (this is why - I need to strip the comma out (which is acceptable in the field, so cant use logic to stop it - I want to replace it with something so I can keep my comma delimited postback)
(formData is of type FormCollection)
var arrayOfValues = formData["x.Value"].Split(',');
So as its a comma delimited value - sometimes that value will be Fred Jones, 1 New Street -> perfectly acceptable entry for what I need, however destroys my comma delimited response.
Any help would be hugely appreciated. This isn't my area of preference at all!
If you want to amend before it hits your controller, you will need to use Javascript/Jquery to catch the form submit and then amend the value before performing the submit.
You could always change the model in the post method, but bear in mind that the modelstate will be used under the hood if you want to check for any errors or send the model back the view.
If you go this route and change the model in the controller then look at clearing the changed field in the modelstate or clearing the whole modelstate before going back to the view, otherwise you won't see your changes and you need to get the model and modelstate to rebind:
model.field1 = newval;
ModelState.Remove("field1");//forces rebind
or
model.field1 = newval;
ModelState.Clear();//clears modelstate fully
So I have this page which will show an individual record from a database. So my URL will look like:
mysite.com/Vehicle/Edit/1
or it may end it 2,3,4,5 etc.. depending on the record its on. Basically I need a link in this page that will take me to another page but have the same value in the url, so it could look like:
mysite.com/Owner/Add/1
Or it could end in 2,3,4,5 etc.. depending on which record the link was in.
How do I do this using C# MVC, im using Razor if that makes any difference.
Thanks
You'll want to use one of the Html.ActionLink helpers.
Say you're passing in a Model to your view that has a property called Id. You could use Html.ActionLink like this:
#Html.ActionLink("Add Owner", "Add", "Owner", new { id = Model.Id }, null)
The first argument is the text that the link will display.
The second argument is the name of the Action to call.
The third argument is the name of the Controller the Action is in.
The fourth argument is the route values for the Action.
The fifth argument is for html attributes. Say you wanted to add a class to your link. Instead of null, you could use new { #class = "my-link-class" }. Notice the # in front of class. That is because class is a reserved word. If you were setting style, you would just do this: new { style = "background-color: #ffffff;" }.
All of this is assuming your Add Action takes in an int id. So something like this:
public ActionResult Add(int id)
{
// Do stuff.
}
Here are the docs for the specific Html.ActionLink overload I used in my example: http://msdn.microsoft.com/en-us/library/dd504972(v=vs.108).aspx
See this post to get the URL. How to get current page URL in MVC 3
Once you have the url, you can just pick off the trailing characters after the final '/'