DotNetNuke MVC Module passing data to different route - dotnetnuke

I'm trying to pass data to a different route. I use form action and Url.Action but that didn't work. It doesn't even route to another view. It works when I use the anchor tag href with Url.Action, but how do I pass data from one Controller method to the same Controller but a different method.

I have a DNN MVC module example on Github for your reference. https://github.com/DotNetNuclear/DnnRestaurantMenu/blob/master/RestaurantMenu.MVC. You can easily install it by finding the install package under the Releases link.
If you look at the default/index view, there is a link to open the Edit view. If passed an item ID, it will load the data into the edit form, otherwise, with no item ID, it considers it a new (add) item.
So in my View.cshtml, I use DNN's Url.Action helper which forms the button's href. (https://github.com/DotNetNuclear/DnnRestaurantMenu/blob/master/RestaurantMenu.MVC/Views/Menu/Index.cshtml)
<a class="btn btn-default" href="#Url.Action("Edit", "Menu", new {ctl = "Edit", itemId = item.MenuItemId})">#Dnn.LocalizeString("EditItem")</a>
The first parameter is the module control key/action. The second is the controller name. In the 3rd parameter of Url.Action we pass the control type and then any number of additional querystring parameters. In this case, the item Id that is in the view's model.
In my MenuController's Edit() action, I can then take that item ID parameter to lookup the item model from the database and then return the Edit view.
public ActionResult Edit(int itemId = -1)
{
...
if (itemId > 0)
{
item = _menuController.GetItem(itemId, CurrentModuleId);
}
...
}

The only way I have every been able to do this with no headache is to create a routerconfig.cs:
using DotNetNuke.Web.Mvc.Routing;
using RouteParameter = System.Web.Http.RouteParameter;
namespace CodeWompler.CW.GridTest
{
public class RouteConfig : IMvcRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapRoute(
moduleFolderName:"CW.GridTest",
routeName: "CW.GridTest",
url: "{controller}/{action}/{id}/{userid}/{itemid}",
defaults: new {
id=RouteParameter.Optional,
userid=RouteParameter.Optional,
itemid=RouteParameter.Optional
},
namespaces: new[] {"CodeWompler.CW.GridTest.Controllers"});
}
}
}
Then, in my index.cshtml, for instance, I can do this:
$.ajax({
url: `/DesktopModules/MVC/CW.GridTest/IMMUser/EditUserById/userid/${myUserId}`,
method: "Post",
headers: {
"ModuleId": moduleId,
"TabId": tabId,
"RequestVerificationToken": rvtoken,
"userId": id //if we were to specify Edit as our url, then we would need this since Edit() takes no parameters and instead, looks in the header for it's data.
}
or
/DesktopModules/MVC/CW.GridTest/IMMUser/EditUserById/${myUserId}
or
/DesktopModules/MVC/CW.GridTest/IMMUser/AssignItemToUser/userid/${myUserId}/itemid/${myItemId}

Related

backbone fetch on a nested route

I have a Sitesand a Positionscollection. Each time the user selects a new site, the id is sent to the refreshPositions method which is in charge of doing the fetch call.
The route to get the positions look like this '.../sites/1/positions'
view.js
refreshPositions: function(siteId) {
this._positions.fetch({
success: this.onPositionsFetchSuccess.bind(this),
error: this.onPositionsFetchError.bind(this)
});
},
So refreshPositions is called whenever I need to update the positionson the page and the siteId parameter has the id, I just don't know to tell fetch to route to something like .../sites/n/positions where n would be the siteId .
Sorry if I missed relevant informations for my question, I'm pretty new to backbone.
I see, so you are calling fetch from your Positions Collection. The out-of-the-box functionality there is to fetch the whole collection (every Position object) if you have a RESTfull api set up. If you want more specific behaviour from your collection, you can probably write it into the Collection object definition.
var PositionCollection = Backbone.Collection.extend({
initialize: function(models, options) {
this.siteId = (options && options.siteId) || 0;
},
url: function() {
if (!this.siteId) {
return '/positions'; // or whatever
}
return '/sites/' + this.siteId + '/positions';
},
// etc...
});
Then, assuming that _positions refers to an instance of PositionCollection you can do:
refreshPositions: function(siteId) {
this._positions.siteId = siteId; // or wrap in a setter if you prefer
this._positions.fetch({
success: this.onPositionsFetchSuccess.bind(this),
error: this.onPositionsFetchError.bind(this)
});
},

Backbone get model not by ID

I have a backbone model of a patient, which I can use to pull patients from my Mongo database. But in addition to polling them by ID, I would like to be able to pull them by name. The only way I could think of doing this is to do something like:
class Thorax.Models.Patient extends Thorax.Model
urlRoot: '/api/patients'
idAttribute: '_id'
fetch: (options = {}) ->
if #get 'first' # has first name, lookup by that instead of id
#urlRoot = '/api/patients/by_name/' + (#get 'first') + '/' + (#get 'last')
#set '_id', ''
super options
But overriding the urlRoot seems bad. Is there another way to do this?
you may just use Backbone.Model#url as a method and apply all your logic there.
So if it is first name in the model use one url and else use default url root.
Here is jsbin code for this (just convert to your CoffeeScript)
You may open network tab to see 2 XHR requests for 2 models I created they are different.
var Model = Backbone.Model.extend({
urlRoot: 'your/url/root',
url: function() {
// If model has first name override url to lookup by first and last
if (this.get("first")) {
return '/api/patients/by_name/' + encodeURIComponent(this.get('first')) + '/' + encodeURIComponent(this.get('last'));
}
// Return default url root in other cases
return Backbone.Model.prototype.url.apply(this, arguments);
}
});
(new Model({ id: 1, first: 'Eugene', last: 'Glova'})).fetch();
(new Model({ id: "patient-id"})).fetch();
Also you may apply this logic to the url in fetch options. But I don't think it is good way.
Happy coding.

How to generate a query string in a view from a scope object?

in my view I've got a scope object which contains the params of my query.
What is the easiest way to generate a href attribute using it in a link in my view?
$scope.search_params // => { q: "test", order: "asc", filter: "price" }
// in my view I want to generate a link like this.
...
thanks.
You could use the ng-href directive :
<a ng-href="/search?q={{ search_params.q }}&order={{ search_params.order }}&filter={{ search_params.filter }}">...</a>
If you want to customise your URL (when for example parameters are missing), you should create a custom function in your controller and refer it in the view.
Something like this :
$scope.myHref = function () {
var res = '?';
if (search_param.q) {
res = res + 'q=' + search_param.q;
}
...
}
<a ng-href="/search{{ myHref() }}">...</a>
I think that the first solution is much cleaner, and you should check the given URL after to check if it's null.
More info from the docs.

How to pass View Param to View Model DataSource in Kendo Mobile?

What is the correct way to pass a view variable from the URL to a View Model to filter the result?
For example:
dataSource: new kendo.DataSource( {
transport: {
read: {
url: 'http://api.endpoint.com/resource',
}
parameterMap: function(options,type) {
if (type === 'read') {
return {
FormID: view.params.FormID
};
}
}
});
In the example above, there's a parameter in the URL called "FormID" and I would like to pass that value right to the parameterMap function. There is no "view" object, so I'm just putting that as an example.
I tried hooking into to the "data-show" and "data-init" functions to set this value to use, but the datasource fetches the data before these functions run.
Thanks
The configuration option options.transport.read can be a function, so you can compose the url there:
dataSource: new kendo.DataSource({
transport: {
read: function (options) {
// get the id from wherever it is stored (e.g. your list view)
var resourceId = getResourceId();
$.ajax({
url: 'http://api.endpoint.com/resource/' + resourceId,
dataType: "jsonp",
success: function (result) {
options.success(result);
},
error: function (result) {
options.error(result);
}
});
}
}
});
To connect this with your list view, you could use the listview's change event:
data-bind="source: pnrfeedsDataSource, events: { change: onListViewChange }"
then in viewModel.onListViewChange you could set the appropriate resource id for the item that was clicked on:
// the view model you bind the list view to
var viewModel = kendo.observable({
// ..., your other properties
onListViewChange: function (e) {
var element = e.sender.select(); // clicked list element
var uid = $(element).data("uid");
var dataItem = this.dataSource.getByUid(uid);
// assuming your data item in the data source has the id
// in dataItem.ResourceId
this._selectedResource = dataItem.ResourceId;
}
});
Then getResourceId() could get it from viewModel._selectedResource (or it could be a getter on the viewModel itself). I'm not sure how all of this is structured in your code, so it's difficult to give more advice; maybe you could add a link to jsfiddle for illustration.
You may use a "global" variable or a field in the viewmodel for that purpose. Something like
var vm = kendo.observable({
FormID: null,
dataSource: new kendo.DataSource( {
transport: {
read: {
url: 'http://api.endpoint.com/resource',
}
parameterMap: function(options,type) {
if (type === 'read') {
return {
FormID: vm.FormID
};
}
}
})
});
function viewShow(e) {
vm.set("FormID", e.view.params.FormID);
// at this point it is usually a good idea to invoke the datasource read() method.
vm.dataSource.read();
}
The datasource will fetch the data before the view show event if a widget is bound to it. You can work around this problem by setting the widget autoBind configuration option to false - all data-bound Kendo UI widgets support it.

Sencha: Set Dataview XTemplate when created Dynamically

I have some data that I'm getting from the server that depending on the situation may bring different fields, so what I have is this:
//This is the way i'm attaching the newly created template to the view
//Still no success
function processDataMethod(response){
//some processing here...
var details = Ext.widget('details');
details.config.itemTpl = new Ext.XTemplate(tplFields);
}
Ext.Ajax.request({
url: '...',
...,
success: function (response, request) {
var combinedData = processDataMethod(response);
operation.setResultSet(Ext.create('Ext.data.ResultSet', {
records: combinedData,
total: combinedData.length
}));
operation.setSuccessful();
operation.setCompleted();
if (typeof callback == "function") {
callback.call(scope || that, operation);
currentList.up().push(Ext.widget('details'));
}
}
});
Any help is appreciated, thanks!!
You have to make a distinction between a number of things:
currentList.up() returns a DOM element (Ext.dom.Element). This has no method push().
With Ext.widget('details', config); you can pass a config like {itemTpl: yourTemplate, data: yourData} to create an instance with a custom template and custom data.
To update your component after creation you can always do someWidget.update(data);.
A component can be rendered to an HTML element with the renderTo option.
A component can be appended to existing components in different ways and you can update the whole layout or parts of it in different ways. This is unnecessary if you are rendering to an HTML element.
Does that help you find your problem?

Resources