I'm using MVC4 with C# and I have a shared _Layout view that has a link to the home page, "index" via the "homeController".
<p class="site-title">
#if (controller = Roles) {
<a href="~/Roles/Index/" id="logo-holder">
} else {
<a href="~/Home/Index/" id="logo-holder">}
<img class="navbar-header" alt="logo"
src="~/Images/Comtrex_Logo_Blue_&_Orange.png" height="60"
width="302">
<span style="padding-top:2em">Cloud Reporting</span>
</a>
</p>
How can I add and if else statement to navigate to different links depending on the view that the user is currently on?
Related
I have an image which when clicked, redirects to another page. I need a way to know whether the link is internal(page of the application) or an external link. If the link is external I would want it to pop up in a new tab and if it is internal pop up in the same tab.
This is the code section.
<a class="lnkImage" href="#item.ImageURL" target="_blank">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
ImageURL and Actual image are coming from the model. Basically I want this functionality.
if(External)
{
<a class="lnkImage" href="#item.ImageURL" target="_blank">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
}
else if(internal)
{
<a class="lnkImage" href="#item.ImageURL">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
}
I am aware that by using Request.Url.Host I can get the host and compare it, but that would mean hard coding it and will have to be changed in different hosts. Is there a way to generically find out the domain of #item.ImageURL in the view?
UPDATE: I can do the Request.URL for both the domain of the website I am and the domain of the #item.ImageURL in the controller and set a boolean in my model, but I have 4 such sections. One link for the image, one for the image header, one for the image details and so on. So this will have me introduce 4 new model objects, set each one of them in the controller. So i want it to be possible to compare it in the view.
Please review this one.
It compares href with window.location.origin using indexOf. If it is found, it changes the window.location = href, if not it triggers anchor.click()
var ls = Array.from(document.querySelectorAll(".lnkImage img"));
ls.forEach(function(l) {
l.addEventListener('click', function(e) {
var ori = window.location.origin;
var hr = this.parentNode.href;
if (hr.indexOf(ori) >= 0) {
window.location = hr;
console.log('internal');
} else {
this.parentNode.click();
console.log('external');
}
})
})
<!--internal-->
<a class="lnkImage" href="http://stacksnippets.net" target="_blank">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
<!--external-->
<a class="lnkImage" href="http://othersite.com/test" target="_blank">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
My answer is server-based. The controller, which fills the view with model, compares for each image item.ImageURL host with current Request.Url.Host. If they are different (link is external), add attribute to the image link target="_blank", if the same - it adds target="_self". See sample code below, you can easily adjust it to your needs.
//controller
public ActionResult Index() {
var model = new CustomModel {
ImageItems = GetImageItems()
};
//set link target for view based on image url
foreach (var imageItem in model.ImageItems) {
imageItem.LinkTarget = GetLinkTarget(imageItem.ImageURL);
}
return View(model);
}
private string GetLinkTarget(string linkUrl) {
var url = new Uri(linkUrl);
return url.Host == Request.Url.Host ? "_self" : "_blank";
}
//view
<div>
#{
foreach (var imageItem in Model.ImageItems) {
<a class="lnkImage" href="#imageItem.ImageURL" target="#imageItem.LinkTarget">
<img id="PrivateimgPreview" src="#item.ActualImage" />
</a>
}
}
</div>
I am using fancyBox with jQuery v3.0.0. for open fancy box at ajax call.
HTML
<a href='/CandidateNote/UDFAndCandidateNote?candidateId=10' class='fancybox fancybox.ajax' title='Notes'>Add Note</a>
C# function
[UserAuthorize]
public ActionResult UDFAndCandidateNote(int candidateId)
{
var Model ="";
---------------------
return Content(this.RenderPartialViewToString("Editor.cshtml", Model));
}
Partial view CSHTML
#{
var i = 0;
Layout = null;
Model.IsAjax = true;
}
<div style="width:600px;min-height:250px">
<div class="fontPadding" style="padding-left: 15px;">
<span id="noteHead" class="selectedHead">NOTES</span> /
<span id="udfHead" class="unSelectedHead">USER DEFINED FIELDS</span>
</div>
</div>
It does not open the fancyBox. It redirect to a page with the action name at controller for jquery V3.0.0 with fancy v2.1.5.
NOTE
If I use the jquery v1.8.3 it works fine.
Is there any problem with jquery version?
I am currently using knockoutjs with one of my MVC applications.
The Layout template looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="container-fluid head-content">
<div class="row">
<div class="col-xs-6">
<img class="img-responsive" src="~/Images/logo.jpg" />
</div>
<div class="col-xs-3">
<a class="block" href="#" style="display: none" data-bind="visible: showBack, click: goBack">
<div class="block-text">
<h4>Back</h4>
</div>
</a>
</div>
<div class="col-xs-3">
<a class="block" href="#" style="display: none" data-bind="visible: showHome, click: navigateToHome">
<div class="block-text">
<h4>Home</h4>
</div>
</a>
</div>
</div>
</div>
<div class="container-fluid body-content">
#RenderBody()
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
</html>
and my Index partial looks like this:
#Html.Partial("_Login")
#Html.Partial("_Home")
#Html.Partial("_CutLengths")
#Html.Partial("_MoveStock")
#section scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/app")
}
My problem is that depending on which page I am on, I would like to use the back button to go to another page. For example, if I am on cutLengths I would want the back button to take me home.
My app.viewmodel.js has a method which looks like this:
// Other operations
self.addViewModel = function (options) {
var viewItem = {},
navigator;
// Add view to AppViewModel.Views enum (for example, app.Views.Home).
self.Views[options.name] = viewItem;
// Add binding member to AppViewModel (for example, app.home);
self[options.bindingMemberName] = ko.computed(function () {
if (self.view() !== viewItem) {
return null;
}
return new options.factory(self, dataModel);
});
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () {
self.view(viewItem);
};
}
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
self["navigateTo" + options.name] = navigator;
};
What I would like to do is pass a string from the ViewModel I am currently viewing which when the back button is pressed will know to direct me to the right ViewModel.
Is it possible to do this?
I hope I have explained it well, if I haven't please ask and I will try harder :D
You can use either ViewData or ViewBag for passing data from the controller to view. So one option is to just add a few dynamic properties to ViewBag for current view model and prior view model.
ViewData is a dictionary of objects that are stored and retrieved using strings as keys.
ViewBag uses the dynamic feature that was introduced into C# 4.It allows an object to have properties dynamically added to it. I would use this for passing your view model state around.
Neither provide compile time checking, which is the beauty of them, you can add anything you want. With that said it’s always good practice to use strongly typed view models over ViewBag and ViewData.
If you'd rather put something in your view model instead of adding properties to ViewBag, than just add another property in each view model called PreviousViewModel and populate it any time you use the model.
Examples using ViewBag or ViewData
ViewData["LastViewModel"] = "CutLengths";
ViewBag.LastViewModel = "CutLengths";
Access your ViewBag in the Views is no problem, they have global scope. ViewBag is like a global variable that you can attach anything to-- so I'd use them judiciously-- maybe some type of a singleton application manager would be a better design.
Hope this helps
I have solved this now. First I changed my HTML
<div class="col-xs-3">
<a class="block btn-back" href="#" data-bind="visible: showBack, click: goBack"></a>
</div>
<div class="col-xs-3">
<a class="block btn-home" href="#/home" data-bind="visible: showHome"></a>
</div>
Then I edited my app.viewmodel.js file and added these
// Data
self.back = ko.observable(null);
// UI state
self.showBack = ko.observable(true);
self.showHome = ko.observable(true);
self.goBack = function () {
if (self.back()) {
window.location.href = self.back();
} else {
window.history.back();
}
self.back(null); // Reset
};
self.setBackUrl = function (url) {
self.back(url);
}
Then on my addViewModel navigate function, I added this:
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () { // This is our navigator function which sets the current view
self.showBack(true);
self.showHome(true);
self.error(null); // Reset errors
self.view(viewItem);
};
}
And then in my other view models, I just make a call to setBackUrl like this:
app.setBackUrl("#/cut-lengths");
And if I want to hide my buttons, that is easy too. I just create a navigatorFactory on the viewModel like this:
app.addViewModel({
name: "Home",
bindingMemberName: "home",
factory: HomeViewModel,
navigatorFactory: function (app) {
return function () {
app.showBack(false);
app.showHome(false);
app.error(null);
app.view(app.Views.Home);
}
}
});
I am pretty new in C# and .NET MVC framework and I have the following problem.
I have a first JQuery Mobile view that show a navbar containing some tabs. Into one of this tab I putted a ListView that show the element of a collection of DataModel.Vulnerability.Fix objects represented by the Model.VulnerabilityFixes into my model object. On the right of every element of the list I have put a button/link to delete the related Fix object that generate this row in the list.
This work fine and I obtain the following result (I post a screenshot):
This is the code of the previous tab (the one that show the Fix list):
<!-- TAB-2: FIXES, SOLUTION e MITIGATING STRATEGY: -->
<div id="tab-2" class="ui-body-d ui-content">
<h3>Fixes</h3>
<a href="#Url.Action("SearchCPE", "Asset", new { id = Model.Id })" data-icon="plus" data-inline="true" data-mini="true" data-role="button" >Aggungi un Fix</a>
<!-- Tabella contenente la lista delle fix: -->
<ul data-role="listview" data-inset="true" data-theme="b" data-split-icon="delete">
#foreach (DataModel.Vulnerability.Fix item in Model.VulnerabilityFixes)
{
<li><a href="#Url.Action("Details", "Product", new { Title = item.Title })">
<h2>#item.Title</h2>
<table style="width: 100%">
<tr>
<th>Id</th>
<th>FixName</th>
<th>Vendor</th>
<th>Version</th>
</tr>
<tr>
<td>#MyHelper.decodeNull(item.Id)</td>
<td>#MyHelper.decodeNull(item.FixName)</td>
<td>#MyHelper.decodeNull(item.Vendor)</td>
<td>#MyHelper.decodeNull(item.Version)</td>
</tr>
</table>
</a>
Delete
</li>
}
</ul>
</div>
<!-- /tab-2 -->
Ok, now I have a DeleteFix() method into the EditingController class that handle the request generated clicking od the Delete button.
This one:
public ActionResult DeleteFix(long vulnId, int currentFixId, string currentFixName)
{
DataModel.Vulnerability.Fix model = new DataModel.Vulnerability.Fix();
manager.openConnection();
try
{
model.Id = currentFixId;
model.FixName = currentFixName;
}
finally
{
manager.closeConnection();
}
return View(model);
}
This method show another view, the DeleteFix.cshtml file, that show a confirm window where is asked to the user to confirm the delete operation or if come back to the previous page, this is the code:
#model DataModel.Vulnerability.Fix
#{
ViewBag.Title = "DeleteFix";
Layout = "~/Views/Shared/MasterPageMobile.cshtml";
}
<h1>Delete Fix</h1>
<h2>Fix: #Model.Title (id: #Model.Id)</h2>
<p>
Confermare la cancellazione del fix "#Model.FixName" ?
</p>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<input type="hidden" name="id" value ="#Model.Id" />
<div data-role="controlgrup" data-type="horizontal" data-mini="true">
<a href="#Url.Action("Index", "Editing", new { id = Model.Id })" data-inline="true" data-mini="true" data-role="button" >Torna alla lista</a>
<a href="#Url.Action("Details", "Groups", new { id = Model.Id })" data-mini="true" data-inline="true" data-role="button" >Annulla</a>
<input type="submit" value="Delete" data-mini="true" data-inline="true" />
</div>
}
My problem is that I want that if the user click on the Torna alla lista button it have to be taken to the initial view that show the list of Fix object but I can't do it
Someone can help me to understand what am I missing? What can I do to obtain this result?
Tnx
Basically I would add a new property in the viewmodels used in the secondary views to have a trace of the primary url :
public string BackUrl { get; set; }
Maybe if you want this feature for more that I secondary view, you can create a base view model that all secondary viewmodels inherit.
Then, when calling a secondary view, just initialize the BackUrl property :
Delete
In the end, in the DeleteFix action, redirect to the BackUrl instead of redering the view (if the viewstate is valid :
public ActionResult DeleteFix(long vulnId, int currentFixId, string currentFixName)
{
if (ModelState.IsValid)
{
DataModel.Vulnerability.Fix model = new DataModel.Vulnerability.Fix();
manager.openConnection();
try
{
model.Id = currentFixId;
model.FixName = currentFixName;
}
finally
{
manager.closeConnection();
}
return Redirect(viewModel.BackUrl);
}
// Invalid viewstate, re-render the view
return View(model);
}
The Scenario is this...I goto the login screen on my web app. I login with wrong username/password. I get an error on the line in my HTML for tab-6 #HTML.Partial("../../Account/Register") because the RegisterModel is not passed in(Exact error below). Well I'm not doing anything with the Register screen, just logging in.
However, I think the problem is because the Register section is always loaded. So I'm thinking, I don't need to pass in both LogOnModel and RegisterModel, to fix the problem, but maybe should not load the Register page until it is specifically called, I think? Is that the correct thing to do and how would I load the Register page only when it is called/clicked. I'm using JQuery UI tabs and asp.net mvc.
ERROR:
The model item passed into the dictionary is of type 'Portal.Web.Models.LogOnModel', but this dictionary requires a model item of type 'Portal.Web.Models.RegisterModel'.
Thanks a lot!
<div id="tabs" class="ui-tabs ui-widget ui-widget-content ui-corner-all" style=" position:relative; border:0px;" >
<ul class="ui-tabs-nav">
<li><a href="#tabs-1" >Home</a></li>
<li><a href="#tabs-2" >Statistics</a></li>
<li><a href="#tabs-3" >Topo Maps</a></li>
<li><a href="#tabs-4" >FAQs</a></li>
<li style="display:none;">Login</li>
<li style="display:none;">SignUp</li>
</ul>
<div id="tabs-1" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Home/Home") </div>
<div id="tabs-2" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Statistics/Statistics")</div>
<div id="tabs-3" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Maps/Maps")</div>
<div id="tabs-4" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Home/FAQs")</div>
<div id="tabs-5" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Account/LogOn")</div>
<div id="tabs-6" class="ui-tabs-hide ui-tabs-panel">#Html.Partial("../Account/Register")</div>
</div>
Here is my AccountController with action method
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
return View(model);
}
As Requested Here is the additional code:
public ActionResult LogOn()
{
return View();
}
Double-check that you've set your partial view to inherit from the appropriate model. At the top of your partial view code, you should have a line like this.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Portal.Web.Models.LogOnModel>" %>