Yesod: parametric handler in julius templates - templates

I am quite new to Yesod and currently try to develop a frontend website and a backend restful webservice. To access the API from the website I use AJAX requests. For the URLs of the requests I want to use shakespearean template like calls:
$.ajax({
url: '#{PersonR}',
type: 'GET',
contentType: "application/json",
data: JSON.stringify({...}),
success: function (data) {...}
});
On the backend site the route to my PersonR handler is defined as follows:
/api/person/#Int/get PersonR GET
For this to work the handler has a signature like
getPersonR :: Int -> Handler Value
However now the julius template needs a parameter to be a valid. I experimented a bit and found that I can directly use haskell code also in #{...}. Maybe I missed that point in the doku.
Question 1: Is there a way to tell that one of the parameters could be given in JavaScript? Maybe with a renderer to output something like this:
function(var1){return '/api/person/'+var1+'/get';}
I think this lacks the point of type safety though. Which leads to my second question (which kinda negates the first): Is there any other way to achieve getting data into the URLs on the client side?

I haven't used this package much, but yesod-js-routes seems like it fits the bill. Basically the package takes your routes file and generates Javascript functions you can use to create the URLs.
The package hasn't seen active development in awhile, but based on testing it still works fine. It's not on Hackage, but it's one file, so I just copied it into my project (I also needed to add import Prelude to that file, and add mtl to my build-depends section of the Cabal file). The README of the project covers the basic integration of the package you need to do.
Here's some example output. For this routes file:
/static StaticR Static appStatic
/auth AuthR Auth getAuth
/favicon.ico FaviconR GET
/robots.txt RobotsR GET
/ HomeR GET POST
/comments CommentR POST
/jsRoutes JSRoutesR GET
/test/#Text/#Integer TestR GET POST
I got this Javascript:
;
var jsRoutes = {}; /* Subsite not supported */ ; /* Subsite not supported */ ;
jsRoutes.FaviconR = {
get: function() {
return {
method: "get",
url: "/favicon.ico/"
};
}
};
jsRoutes.RobotsR = {
get: function() {
return {
method: "get",
url: "/robots.txt/"
};
}
};
jsRoutes.HomeR = {
get: function() {
return {
method: "get",
url: "/"
};
},
post: function() {
return {
method: "post",
url: "/"
};
}
};
jsRoutes.CommentR = {
post: function() {
return {
method: "post",
url: "/comments/"
};
}
};
jsRoutes.JSRoutesR = {
get: function() {
return {
method: "get",
url: "/jsRoutes/"
};
}
};
jsRoutes.TestR = {
get: function() {
return {
method: "get",
url: "/test/" + arguments[0] + "/" + arguments[1] + "/"
};
},
post: function() {
return {
method: "post",
url: "/test/" + arguments[0] + "/" + arguments[1] + "/"
};
}
};
For a route like TestR, you can call:
jsRoutes.TestR.get("a",2).url
to return
"/test/a/2/"
Unfortunately, neither the generated Javascript nor Javascript the language is doing anything to protect against e.g. passing 3 arguments to that function, or passing arguments of the wrong type. I don't know what your expectations are, but the Javascript code generation looks simple enough that you could improve what's generated.

Related

Loading Remote Data using Select2 and Webservice

I am using Select2 4.0.3 in my web forms .net application. I am trying to Load Remote data using a webservice, but its not working as expected.
First Issue am facing is that the webservice method is not getting called and am getting a console error:
System.InvalidOperationException: Missing parameter: text.
at System.Web.Services.Protocols.ValueCollectionParameterReader.Read(NameValueCollection collection)
at System.Web.Services.Protocols.HtmlFormParameterReader.Read(HttpRequest request)
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
So I tried removing the paremeter from the webservice call
<WebMethod()> _
Public Function GetDataFromService() As String
Doing this the method got fired, but still the items in the select2 did not get populated (screenshot atached).
Can someone help me to figure out where am I making a mistake.
Here are the details:
Select2 Code in the Webform:
$("#ddlEntity").select2({
ajax: {
url: "Service/InvoiceHTMLService.asmx/GetDataFromService",
type: 'POST',
delay: 250,
params: {
contentType: 'application/json; charset=utf-8'
},
dataType: 'json',
data: function (term, page) {
return {
text: term,
};
},
processResults: function (data, params) {
// parse the results into the format expected by Select2
// since we are using custom formatting functions we do not need to
// alter the remote JSON data, except to indicate that infinite
// scrolling can be used
params.page = params.page || 1;
return {
results: data.items,
pagination: {
more: (params.page * 30) < data.total_count
}
};
},
cache: true
},
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
minimumInputLength: 1,
templateResult: formatRepo, // omitted for brevity, see the source of this page
templateSelection: formatRepoSelection // omitted for brevity, see the source of this page
});
WebService Method:
<WebMethod()> _
Public Function GetDataFromService(text As String) As String
Return "{['id':1, 'text':'Test1'],['id':2, 'text':'Test2']}"
End Function
Try this please
var fd = new FormData();
fd.append("text",term);
ajax: {
url: "Service/InvoiceHTMLService.asmx/GetDataFromService",
type: 'POST',
delay: 250,
params: {
contentType: 'application/json; charset=utf-8'
},
dataType: 'json',
data: fd
...
I think you did not create template for this select2. since you are using templateResult and templateSelection it requires template or you can remove those two options.
For your reference : https://select2.github.io/examples.html#templating
Updated:
they have changed query callback from
data: function (term, page) {
return {
text: term,
};
},
into
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},

Modify Strongloop/Loopback built-in input arguments in API Explorer

I want to know if it is possible to change the default input parameters of builtin methods like 'create', but only for input (not using the hidden property) and only for this method. In this case, I want to suppress the "balance" parameter. In other words, in the pointed location, my api explorer needs to show the following:
{
"userId": "string"
}
I have managed change custom remote methods, like so:
Using the following code:
module.exports = function(User) {
User.makeDeposit = function(data, callback){
//Method logic
};
User.remoteMethod(
'makeDeposit',
{
http: {path: '/makedeposit', verb: 'post'},
returns: {type: User, default:'User', root: true},
accepts: {arg: 'req', type: 'object', default: prettyJSON(depositSchema), http: {source: 'body'}}
}
);
};
// Returns a pretty printed json
function prettyJSON(str){
return JSON.stringify(str, null, ' ');
}
// Input Schemas - Only used for API Explorer
var depositSchema = {};
depositSchema.userId = "hash123";
depositSchema.amount = 11.37;
But I cannot replicate for built-in methods. Any help?

Return Partial View with ajax call

I want to return a Partial View in ajax call in Sitecore, I am already using web APIs, i can return JSON object, but i want to return the view with HTML :
[HttpGet]
public ActionResult StoreSearchResultsPartial()
{
return PartialView("/views/components/StoreSearchResults.cshtml");
}
my ajax call :
var ajaxUrl = "/api/sitecore/components/StoreSearchResultsPartial"
$.ajax({
type: "GET",
url: ajaxUrl,
contentType: "application/json; charset=utf-8",
success: function (result) {
$("#searchResults").html(result);
},
error: function (result) {
}
});
i am using web API for other functionalities, so i added my routing :
public void Process(PipelineArgs args)
{
var config = GlobalConfiguration.Configuration;
RouteTable.Routes.MapHttpRoute(
name: "NamedActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandler();
config.Routes.MapHttpRoute("DefaultApiRoute",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
When I comment this routing everything is working fine.
It is working fine now, I changed my routing to start with something not "api", so i changed this api/{controller}/{action}/{id} to be mywebapi/{controller}/{action}/{id}, then i was able to call : /api/sitecore/components/StoreSearchResultsPartial

Is it possible to have a Ember.TEMPLATES proxy?

I'm developing an app with Ember 1.0.rc3 and I'm loading my precompiled Handlebars template files from my backend server on demand via Ajax requests. To be able to handle this, I created my own template manager, which is pulling the templates from the server and stores them in Ember.TEMPLATES.
Now, this is working pretty good, but for the sake of lazyness I wonder if there is a possibility to hook into some code within the Ember framework and put my template manager as a proxy in front so that every time when Ember does it's magic, its doing this by accessing my manager first?
EDIT:
Here's some code, basically my template manager is just a class, which - as I said - loads the precompiled templates from the server and places them into the Ember.TEMPLATES template cache.
fetchTemplate: function (templateName, templateAlias) {
var alias = templateAlias || templateName;
var retString = '';
// check if the template already exists
if (typeof Ember.TEMPLATES[alias] === 'undefined') {
// create the ajax request object
$.ajax({
type: 'GET',
data: { templateName: templateName },
url: 'template/request',
success: function(data) {
if (typeof data.template === 'string' && data.template !== '') {
var escapedTemplateString =
data.template.replace(/\\n/g, "\\n").replace(/\\r/g, "\\r").replace(/\\t/g, "\\t");
escapedTemplateString = escapedTemplateString.replace(/\s+/g, " ");
// load the template into the Ember.TEMPLATES template cache
Ember.TEMPLATES[alias] = Ember.Handlebars.template(eval("(" + escapedTemplateString + ")"));
retString = alias;
} else {
retString = '';
}
}
});
} else {
retString = alias;
}
return retString;
},
releaseCache: function() {
Ember.TEMPLATES = {};
}
Implementing a custom resolver (or subclassing the default resolver) would let you tap into Ember's process for finding templates. However, I don't think you would be able to successfully integrate your approach because resolving is expected to be synchronous.

cannot get the web service response

i surely an committing a very lame mistake but couldn't figure out where...
here is my web method
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public int Add(int x, int y) {
return x + y;
}
and im calling it via ajax like this
$.ajax({
type: "GET",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: { x: 4, y: 5 },
url: 'http://localhost:14436/Service1.asmx/Add',
success: function (data) {
alert('success');
var d = $(data);
console.log(d);
}
});
the problem is i cannot get the returned data in success,
in fiddler its showing {"d":9} but i keep on getting data empty... what am i doing wrong here... TIA
Edit
my web service is at http://localhost:14436/Service1.asmx and my web application from which im accessing the web service is located at http://localhost:3587/
so i guess this makes it a cross domain request?
try the following function:
function AjaxSucceeded(result)
{
alert(result.d);
}
still not getting any result?
UPDATE:
You can read more about the .d wrapper at:
http://encosia.com/2009/02/10/a-breaking-change-between-versions-of-aspnet-ajax/
Here's the exact sample as what you're trying to achieve:
http://www.joe-stevens.com/2010/01/04/using-jquery-to-make-ajax-calls-to-an-asmx-web-service-using-asp-net/