Calling server side methods using ajax inside a custom extension - dotnetnuke

I am creating a custom extension for DNN using Christoc's DotNetNuke Module and Theme Development Template
I want to call server side methods using ajax inside my javascript file
example code
$.ajax({
url:'myModule/listOfPosts'
success:function() {
// do something with list of posts
}
});
How can i do this? I am open to all suggestions. Thank You

I did a tutorial on exactly this topic. Building DNN framework services for your module and then calling them securely using jquery ajax.
Client-centric module development
Also, I have another example on my website:
Rich-client Module with Knockout

You can also do it using AjaxPro.dll.
Here is the codeplex URL: AjaxPro 2
Design Section:
<asp:CheckBox ID="chkDelete" runat="server" onclick="javascript:deleteRecord();" />
Javascript:
<script type="text/javascript">
function deleteRecord() {
Modules.MyAdmin.ViewCars.deleteCar(); // asynchronous call
}
Code Behind:
namespace Modules.MyAdmin
{
public partial class ViewCars : PortalModuleBase
{
[AjaxPro.AjaxMethod]
public void deleteCar()
{
// Write your action over here
}
}
}

Related

AngularJS: How to initialise components after service finished asynchronous request

We're not using AngularJs as a SPA but embedded module to manage some behavior and shared data, so we're not actually utilising something like angular router. How should I initialize components only after a shared data service finished an asynchronous request? AngularJS was used with Typescript
Angular Module
import ... from '...'
import ... from '...'
...
angular.module('app-1', [])
.service('data-service', DataService)
.component('zeroDateButton', new ZeroDateButtonComponent())
.component('zeroPanel', new ZeroPanelComponent())
.component('zeroChart', new ZeroChartComponent())
ASP.NET Page hosting Angular module
BI.aspx
<asp:Content ID="standardContent" ContentPlaceHolderID="MainContent" runat="server">
...
<zero-date-button></zero-date-button>
<zero-date-button></zero-date-button>
<zero-panel name="panel-1"></zero-panel>
<zero-panel name="panel-2"></zero-panel>
<zero-panel name="panel-3"></zero-panel>
<zero-chart></zero-chart>
...
<script src="Scripts/Components/component.app-1.js) "></script> //compiled angular module js file
</asp:Content>
Page URL: https://www.example.com/BI/Zero
DataService.ts
public tryGetData() {
return $http.get(url).then((res: any) => {
this.panels = res.panels;
});
}
ZeroPanelComponent.ts
...
public $onInit(): void {
this.panels = this.dataService.panels;
this._render();
...
Most of the logics for this module relies on the data from the three components, so I want to fetch and store them all together in the data service, from which each component access the data they need from this service, and let the service figure out the logics and tell each of them by broadcasting the events.
Upon the components initialization(in $onInit method), it should display things using data retrieved from data service. The problem is component initialization is not awaiting data service to finish data fetching, so the component can't get the data they need and render nothing.
Trial with $routeProvider
I've seen seen lot's of people advising $routeProvider with appModule.config(), however it was not working. I'm not sure if this solution will work considering the way we use Angular, but I'm still posting the code snippet.
angular.module('app-1', ['ngRoute'])
.config(($routeProvider) => {
$routeProvider
.when('/BI/Zero', {
template: '<zero-panel class="flex-basis-half marginBottom" panel-name="SalesSnapshot", container-id="sales-snapshot"></zero-panel>',
resolve: {
DataService: (DataService) => {
return DataService.tryGetData();
},
},
});
})
.service('zero-data-service', DataService)
...
and I added ng-view directive to one in BI.aspx
There's NO error in browser, <zero-panel> is not rendered and tryGetDate() is not called too. I found someone said the 'path' defined to when() is part of the URL after the # symbol. Could you verify if this is true?
In terms other solution, the most intuitive thing I can think of is broadcasting an event when data service has obtained the data, and components listen to event to fetch the data, instead of fetching during their initialization.
I appreciate if anyone can suggest if $routeProvider would work in my usecase, or suggest any other possible solution to achieve the goal.

Upgrade existing custom angular Filter using upgrade module

I am using angular's upgrade module to create a hybrid app where both angular js and angular2 can co-exist together.I have a situation here
where i need a existing custom filter to be used for a component.Does the upgrade module support upgrading custom filters.Ifsd so please advice how to do that?
Unfortunately upgrade module doesn't support upgrading filters to Pipes. But Pipes are very similar to filters and are really easy to upgrade manually.
If you need to have co-existing filter & Pipe I suggest to extract all logic & transforms to simple TypeScript / JavaScript:
export class PipeUtils {
static myFilterTransform(value, ...args) {
// return transformed value
}
}
AngularJS filter:
angular.module('app', [])
.filter('myFilter', () => PipeUtils.myFilterTransform)
Angular Pipe:
export class MyPipe {
transform(value, ...args) {
return PipeUtils.myFilterTransform(value, ...args)
}
}

referencing an amd module(arcgis) in webpack app

I'm building a react app with webpack and i need to incorporate arcgis maps into a react component. I have know idea how to bring this into my project. I've tried creating an arcgis directory with an index.js of the built javascript and trying to reference that:
import {Map} from 'arcgis/index'
That doesn't work. I then just tried to include the css/js script tags directly into my index.html but when I try to require them, like in the example, webpack obviously can't find them. Is there some way to tell webpack to ignore require calls in my src file so it gets handled by the browser? I'm trying and failing at doing the following:
import React from 'react'
export default class EsriMap extends React.Component {
componentDidMount() {
const _this = this
require(["esri/map", "dojo/domReady!"], function(Map) {
var map = new Map(_this.refs.map, {
center: [-118, 34.5],
zoom: 8,
basemap: "topo"
});
});
}
render() {
return (
<div ref="map"></div>
)
}
}
You may want to try this https://github.com/tomwayson/esri-webpack-babel .
This method is nice because it doesn't bog down the build. You pull in the ESRI Api from the CDN, and tell webpack that it's an external.
//Add this...
externals: [
// Excludes any esri or dojo modules from the bundle.
// These are included in the ArcGIS API for JavaScript,
// and its Dojo loader will pull them from its own build output
function (context, request, callback) {
if (/^dojo/.test(request) ||
/^dojox/.test(request) ||
/^dijit/.test(request) ||
/^esri/.test(request)
) {
return callback(null, "amd " + request);
}
callback();
}
],
//And this to you output config
output: {
libraryTarget: "amd"
},
When your app loads you bootstrap you webpack modules using Dojo in a script tag.
<!-- 1. Configure and load ESRI libraries -->
<script>
window.dojoConfig = {
async: true
};
</script>
<script src="https://js.arcgis.com/4.1/"></script>
<!-- Load webpack bundles-->
<script>
require(["Angular/dist/polyfills.bundle.js", "Angular/dist/vendor.bundle.js", "Angular/dist/app.bundle.js"], function (polyfills, vendor, main) { });
</script>
I've got it working with an Angular 2 App I'm working on. The only downside is I haven't yet got the unit tests to run right using Karma. I've only been working on that a few hours now.. Hope to have a solution to the testing issue soon.
#getfuzzy's answer will work well as long as you don't need to lazy load the ArcGIS API (say for example only on a /map route).
For that you will want to take the approach I describe in this answer
This blog post explains why you need to use one of these two approaches and explains how they work as well as the pros/cons of each.
I think you can try using bower version of esrijsapi. Doc link

Using RequireJS with AngularJS. Problems loading AngularJS

I am creating a NodeJS app which uses AngularJS for it's front-end. I am Also using RequireJS to load in the JS dependencies and then instantiate the Angular app. Here is what I am trying to do:
Within my HTML file (written in Jade) I include the RequireJS files and then call the RequireJS config using the 'data-main' attribute:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
script(type="text/javascript" src="/bower_components/requirejs/require.js" data-main="/main.js")
My main.js file looks as follows:
"use strict";
function(require) {
require(['/assets/requiredPathsAndShim.js'], function(requiredPathsAndShim) {
require.config({
maps : {
// Maps
},
paths : requiredPathsAndShim.paths,
shim : {
// Modules and their dependent modules
}
});
angular.bootstrap(document, ['appNameInHere']);
});
})(require);
I have an external file which contains an object with my routes '/assets/requiredPathsAndShim.js' and it looks like follows:
"use strict";
(function(define) {
define([], function() {
return {
paths : {
'angular' : '/bower_components/angular/angular'
}
};
});
})(define);
I will add that my NodeJS/Express app has the 'bower_components' folder set to serve static files and this is working fine.
Whenever I try and instantiate the AngularJS app using the 'angular.bootstrap...' method it tells me Angular is not defined. I can't see why this is happening and haven't been able to figure it out yet. O can't see any problem with my routes to the Angular files. Can anyone see or suggest why this may be happening?
Thanks!
Just managed to crack it! I had to place the 'angular.bootstrap' call in a callback function of the require.config method as the app was trying to call AngularJS before it had been defined.
Hope this helps anyone in the future.

AngularJS controller is not reaching webapi

In the interest of crawling before walking with angularjs, I have created a simple application to display results from a sql server table using webapi. unfortunately the webapi is never called, because the routing is wrong, but I am not sure how to resolve. fiddler shows a 404 error.
the cshtml is as follows, defining the app and controller.
<script type="text/javascript">
var app = angular.module('streamApp', []);
app.controller('streamController', function($scope, $http){
$scope.loading = true;
$scope.addMode = false;
//Used to display the data
$http.get('/api/Stream/').success(function (data) {
$scope.streams = data;
$scope.loading = false;
})
.error(function () {
$scope.error = "An Error has occured while loading streams!";
$scope.loading = false;
});
});
</script>
the rendering section in the cshtml file is
<div data-ng-app="streamApp" data-ng-controller="streamController" class="container">
....
</div>
The webapi class is in a folder named WebApi in the MVC project, but since it is never reached, there is no point in displaying its code. it is non-descript anyway.
The route config is as follows:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I am not sure if I need to specify route instructions in angularjs code or in mvc route config, and exactly what functions or configuration to supply. I have tried moving the webapi class to the Controllers folder with the same results - http 404. Any advice on how to make this example get to the webapi code would be appreciated.
well hot-diggity....I solved the immediate problem by adding the annotation to my webapi class method
[Route("api/stream")]
[System.Web.Http.HttpGet]
public IEnumerable<Models.StreamViewModel> Get()
{
.....
}
so now the question is should something be done with RouteConfig as a better practice? Or is the Route() annotation the preferred way to go? or is it 6 of one half a dozen of the other?
Answer to your updated question , Best Practice of routing:
Route() annotation is the preferred way of doing this.
MVC 5 supports a new type of routing, called attribute routing. As the
name implies, attribute routing uses attributes to define routes.
Attribute routing gives you more control over the URIs in your web
application.
The earlier style of routing, called convention-based routing, is
still fully supported. In fact, you can combine both techniques in the
same project.
There are other advantages of attribute routing like
It puts the route information adjacent to the controller action that
implements that route. This helps in debugging and troubleshooting,
as well as providing an ability to quickly search for route
information in your solution.
It reduces risk in the process of making changes to routes. In RouteConfig.cs or WebApiConfig.cs (in the case of Web API solutions),
the possibility exists to inadvertently change the wrong route or
otherwise adversely affect other parts of your application.
You may also want to include acceptable HTTP methods, permitted user types and registration priorities, which if included with the
attribute-based routes, put all of that information together in one
place.
This post provided inspiration and reinforcement for me on the above, and goes into more detail:
http://kevinmontrose.com/2011/07/25/why-i-love-attribute-based-routing/
You can use either, but without the annotation your endpoint would have been api/get not api/stream (assuming you didn't rename your method).
First , you should use ApiController rather then Controller, as it take a role of an api action.
Second, If we take a look, it looks like you created a controller named ApiController, and a function called Stream. Otherwise, its a misunderstanding of the designing your web integration using MVC.
App_Start\WebApiConfig.cs:
using System.Web.Http;
class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
}
}
Global.asax.cs:
using System.Web.Http;
...
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
WebApiConfig.Register(GlobalConfiguration.Configuration);
RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
and ApiControllerNameController: //The Controller word closes the file name, and will be reached without writing it:
using System;
..
..
..
namespace MvcApplication1.Controllers
{
public class ValuesController : ApiController
{
// GET api/values/MethodName
public IEnumerable<int> MethodName()
{
return new List<int> { 1, 2, 3 };
}
}
}

Resources