MVC3 Routing From an area to default - asp.net-mvc-3-areas

Working on an MVC3 project.
I have an area named "Area" with an areaRegistration like this,
context.MapRoute(
"Area_Details",
"Area/{controller}/{AreaId}/{AreaName}/{id}/{action}",
new { controller = "Area", action = "Index" }
);
context.MapRoute(
"Area_default",
"Area/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
I have another controller in /Controller "Home" with action "Details" which returns a PartialView.
From a view in the "Area" area I am trying to
#Html.RenderAction("Details","Home", new{ myId = 1})
which should access /home/details?myId=1
but it is trying to access /area/home/details?myId=1
how can I solve this problem?

I think this will work:
Html.RenderAction("action", "controller", new { area = "" })

Related

SAP UI5: Navigation from Master page and Detail page through two different OData URLs

I am trying to create a Master - Detail page using OData servicea in SAPUI5. Everything works fine in the Master page. Meaning I'm able to populate the list with valid data from SAP backend using an OData URL.
Now what I want to achieve is, to call a second OData URL to fetch the detail values and populate that in the page.
My Master.controller.js
handleListSelect : function (evt) {
var context = evt.getParameter("listItem").getBindingContext();
this.nav.to("Detail", context);
console.log('evt.getSource: ' + evt.getSource());
console.log('evt.getBindingContext: ' + evt.getSource().getBindingContext());
}
Console Output gives
"evt.getSource: Element sap.m.List#Master--list" sap-ui-core.js line 80 > eval:31
"evt.getBindingContext: undefined"
I'm unable to populate values in the detail page from the second URL. Can anyone guide or help me on this?
My Compenent.js
createContent : function() {
// create root view
var oView = sap.ui.view({
id : "app",
viewName : "sap.ui.demo.myFiori.view.App",
type : "JS",
viewData : {
component : this
}
});
// Using OData model to connect against a real service
var url = "/MyFioriUI5/proxy/sap/opu/odata/sap/XXXXXX;mo/";
var oModel = new sap.ui.model.odata.ODataModel(url, true, "", "");
oView.setModel(oModel);
// set i18n model
var i18nModel = new sap.ui.model.resource.ResourceModel({
bundleUrl : "i18n/messageBundle.properties"
});
oView.setModel(i18nModel, "i18n");
// set device model
var deviceModel = new sap.ui.model.json.JSONModel({
isPhone : jQuery.device.is.phone,
isNoPhone : !jQuery.device.is.phone,
listMode : (jQuery.device.is.phone) ? "None" : "SingleSelectMaster",
listItemType : (jQuery.device.is.phone) ? "Active" : "Inactive"
});
deviceModel.setDefaultBindingMode("OneWay");
oView.setModel(deviceModel, "device");
// Using a local model for offline development
// var oModel = new sap.ui.model.json.JSONModel("model/mock.json");
// oView.setModel(oModel);
// done
return oView;
}
My Detail.controller.js
sap.ui.controller("sap.ui.demo.myFiori.view.Detail", {
handleNavButtonPress : function(evt) {
this.nav.back("Master");
},
onBeforeRendering : function() {
// this.byId("SupplierForm").bindElement("BusinessPartner");
},
handleApprove : function(evt) {
// show confirmation dialog
var bundle = this.getView().getModel("i18n").getResourceBundle();
sap.m.MessageBox.confirm(bundle.getText("ApproveDialogMsg"), function(oAction) {
if (sap.m.MessageBox.Action.OK === oAction) {
// notify user
var successMsg = bundle.getText("ApproveDialogSuccessMsg");
sap.m.MessageToast.show(successMsg);
// TODO call proper service method and update model (not part of this session)
}
},
bundle.getText("ApproveDialogTitle"));
}
});
I can't see the second URL you are refering to, but we handle it this way.
In Component.js:
var oView = sap.ui.view({
id: "app",
viewName: "fom.test.app.view.App",
type: "JS",
viewData: { component : this }
});
var dataModel = new sap.ui.model.odata.ODataModel("/fom/fiori/odata/FOM/mobile_app_srv", true);
oView.setModel(dataModel);
This connects the master view to the data for all the list items.
In the App.controller.js we make use of the onNavigation function, defined in Detail.controller.js. That means when routing to the detail view, the onNavigation function is called before the view is set up.
App.controller.js:
to : function (pageId, context) {
var app = this.getView().app;
// load page on demand
var master = ("Master" === pageId);
if (app.getPage(pageId, master) === null) {
var page = sap.ui.view({
id : pageId,
viewName : "fom.test.app.view.view." + pageId,
type : "XML"
});
page.getController().nav = this;
app.addPage(page, master);
jQuery.sap.log.info("app controller > loaded page: " + pageId);
}
// show the page
app.to(pageId);
// set data context on the page
if (context) {
var page = app.getPage(pageId);
page.setBindingContext(context);
try{
var oController = page.getController();
oController.onNavigation(context);
}
catch(e){ }
}
},
Detail.controller.js:
onNavigation: function(context) {
this.getView().bindElement({
path: context.sPath,
parameters: {
select: "Id," +
"Lifnam," +
"Rmwwr," +
"Waers," +
"Sendedatum," +
"Workflowtyp," +
"Sktodat," +
"Stufe," +
"MonFrgstA," +
"Bukrs," +
"Belnr," +
"Gjahr," +
"EdcObject," +
"BstatTxt",
expand: "Positions"
}
});
},
The bindElements() function, connects the detail view to the results of another web service call, which fetches all attributes mentioned in select and the line items which are fetched with the expand.
Now your first webservice call is loading only the data relevant for the master view list, and the second one all the information of the selected list item.
When you use the newer routing functionality of UI5, you will need to find another place for the hook. I haven't built that in yet.
oView.setModel(oModel);
You have this statement twice - the one would override the other - you need to provide an alternate reference to the second instance:
e.g.
oView.setModel(oModel, "local")

How to add ColumnListItem to a table inside a page in MVC from other page controller

I have a SAPUI5 application written in MVC
I have a view called oPage4:
var landscapePage = new sap.m.Page({
title : "Landscape Name",
showNavButton : true,
navButtonPress : [oController.back,oController],
footer : new sap.m.Bar({
id : 'landscapePage_footer',
contentMiddle : [
new sap.m.Button({
}),
new sap.m.Button({
})
]
}),
});
oLandscapePageTable = new sap.m.Table("landscape", {
inset : true,
visible : true,
getIncludeItemInSelection : true,
showNoData : false,
columns : [ new sap.m.Column({
styleClass : "name",
hAlign : "Left",
header : new sap.m.Label({
})
}) ]
});
landscapePage.addContent(oLandscapePageTable);
return landscapePage;
then inside page1 controller I want to add a columnlistitem to the table of page 4.
var oPage4 = sap.ui.getCore().byId("p4");
var landscapePageRow = new sap.m.ColumnListItem({
type : "Active",
visible : true,
selected : true,
cells : [ new sap.m.Label({
text : something
}) ]
});
oPage4.getContent().addItem(landscapePageRow);
it doesn't work. please show me how to do so?
Ok, I think I understood your problem now. In general I would avoid calling the page and doing manipulations on it from another view. However, it is absolutely possible:
Additional functions in your view
You can extend your page4 with some more functions that can be called from outside like this:
sap.ui.jsview("my.page4", {
createContent : function() {
this.table = ...
...
},
addColumnListItem : function(columnListItem) {
// add it to the table calling this.table ...
}
}
From another view you´re now able to call this function like this:
var page4 = sap.ui.jsview("my.page4");
page4.addColumnListItem(page4, columnListItem);
Attention: The page4 object itself doesn´t point to the control you´re returning but to the the view instance itself. You will notice this, if you log the page4 object to the console. This is why you have to add functions like described.
Some other approaches would be to use the EventBus like described here to publish and subscribe to events. Since you´ve asked for it let me show you how you could do it:
Using the EventBus
The main intention is, that one can subscribe to a particular event and others can publish such events to the eventbus. Let me give you an example:
Subscribing to the EventBus:
var eventBus = sap.ui.getCore().getEventBus();
eventBus.subscribe("channel1", "event1", this.handleEvent1, this);
Of course you can name your channel and events as you wish. The third parameter indicates the function, that will be called in case of published events. The last paramter is the scope 'this' will point to in the given function.
Your handleEvent1 function could look like this:
handleEvent1 : function(channel, event, data) {
var listItem = data.listItem
}
Publishing events to the EventBus:
var columnListItem = ...
var eventBus = sap.ui.getCore().getEventBus();
eventBus.publish("channel1", "event1",
{
listItem : columnListItem
}
);
One more option you have is to make the columnListItems depending on a model. Like everytime it depends on your actual architecture and data.
Let me know if this solved your problem or if you need some more information.

Why is #Html.ActionLink leaving off the controller and action portions of the link?

I am creating a link inside the main _Layout.cshtml file inside a MVC3 application.
#Html.ActionLink("Security", "Index", "Home", new { area = "Security" }, new { })
When the page is rendered, this is the resultant Html
Security
and if I click on this link, I get a blank page.
I have routedebugger installed and here are the results:
I have the default route inside the Global.ascx.cs as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "Eis.Mvc.Web" }// Parameter defaults
);
and the Security Area's route:
context.MapRoute(
"Security_default",
"Security/{controller}/{action}/{id}",
new { area = "Security", controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "Eis.Mvc.Web.Areas.Security.Controllers" }
);
If I directly type in the following URL, http://localhost:1410/Security/home, the correct page is presented.
How can I get the #Html.Action link to include the controller portion of the URL?
I do have a Home controller with an Index action inside the root portion of the application and had to include the Namespace filters to the route registrations.
Thank you,
Keith
Change the Security Area's route mapping to the following:
context.MapRoute(
"Security_default",
"Security/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "Eis.Mvc.Web.Areas.Security.Controllers" }
);
Notice the area and controller portions of the defaults parameter were removed.
Now the #Html.ActionLink("Security", "Index", "Home", new { area = "Security" }, new { }) renders Security
Keith

how to have minimum AreaRegistrations with putting duplicated elements in single place

i have several AreaRegistration classes which one each registers own routes and each one have some duplicated elements such as bolded text in below:
context.MapRoute("Search", "**{culture}/{style}**/search",
new
{
**culture = cultureValue,
style = styleValue,**
controller = "search",
action = "default"
},
new
{
**culture = new CultureRouteConstraint(),
style = new StyleRouteConstraint()**
});
how i can have minimum AreaRegistrations with putting duplicated elements in single place which handles that? this is possible?
You can add routes to the Global.asax file and use the area route value. For example:
routes.MapRoute("Search", "{culture}/{style}/search", new
{
culture = cultureValue,
style = styleValue,
controller = "search",
action = "default",
area = "areaName"
});

How do I generate a RouteLink to a route in a different area?

I have two different areas, and I have a route in one of those areas that is specific to that area, but I need to generate a link to that route using Html.RouteLink from another area (it's how you get over into the new area) but it won't work... It doesn't seem possible to use RouteLink to routes in a different area.
What is the best way around this? Should I just define a new route in the other area and name it differently?
UPDATE (code):
In master page in the main area (I've tried it multiple ways, all of which have produced same result):
<a href="<%= Url.Action("Index", "Home", new { area = "CustomerSite", route = "CustomerSite_preview", domain = (string)ViewData["DomainName"] }, null) %>">
In the CustomerSite area registration as the first route registered:
context.MapRouteLowercase(
"CustomerSite_preview",
"preview/{domain}/{controller}/{action}/{id}",
new { area = "CustomerSite", controller = "Home", action = "Index", id = "" },
new { isCustomerSite = new CustomerSiteRouteConstraint() },
new string[] { "GrayHills.CarLotHosting.Web.Areas.CustomerSite.Controllers" }
);
In your route object you just need a property named area with the name of the area.
Html.RouteLink("My Link Text",
new { area = "MyArea", controller = "MyController" ... },
null);
You need to change your route definition - see the answer ASP.NET MVC Url.Action routing error for more info.
In essence, your route should look as follows since you explicitly supply the controller name and action:
context.MapRouteLowercase(
"CustomerSite_preview",
"preview/{domain}/home/index/",
new { area = "CustomerSite"
, controller = "Home"
, action = "Index"},
new { isCustomerSite = new CustomerSiteRouteConstraint() },
new string[] {
"GrayHills.CarLotHosting.Web.Areas.CustomerSite.Controllers"}
The Url.Action will look like
<a href="<%= Url.Action("Index"
, new {domain = (string)ViewData["DomainName"] }
, null) %>">
which will result in a Url like http://localhost:56291/preview/somedomainname/home/index