I have a web-app developed in Angular with Grails at the back serving REST service calls and the root page of the single page apps as well the template html files defined the ui-router. The application has html5mode set to be true. In order have the reload to wok, I add the mapping to UrlMappings.groovy:
"/app1/**"(view:"/app1/index")
/app1 is the base url of the app, /app1/index would be served by grails-app/view/app1/index.gsp, but this cause problem since all template Url's are coded in relative, which means they are also have the prefix /app1 in Url's as well.
Ideally I'd like to have a mapping for /app1/**.html which still maps all template Url to html files under web-app/app1. But I could not find information on how to achieve this. I tried to add
static excludes = ["/**.html"]
But it does not work either.
Anyway to get around this other than to restructure the dynamic Url's and template file Url's to force them to have entirely different prefix?
Your static resources are available for consumption via servlet context. So you could create a controller or a trait to mixin into existing controllers that maps to any of your static templates.
/**
* Render some static content for AngularJS consumption from public folder e.g. "/templates/home.html"
*/
def renderStatic(String fileName) {
try {
response.outputStream << getServletContext().getResourceAsStream(fileName)
response.outputStream.close()
} catch (e) {
render status: NOT_FOUND
}
}
Related
I would like to be abel to run my angularjs app from the app directory from VS code without using VS2015 and without running iis express. This will make it possible to create new UI very fast specially combined with mocking the service layer.
It's a mvc5 + webapi2 application.
So I need to run /app/index.html from mvc. The index.html is a full html page not an angular template.
Create an action method that returns perticular HTML file. You can return File from controller action. have a look:
public ActionResult Index()
{
var result = new FilePathResult("~/Html/index.htm", "text/html");
return result;
}
Also check this Class: FileResult
Hope this helps!
You can simply call:
return Redirect("~/path/to/.html");
2 ways of doing so:
i. Simple replace the original index.html to your new index.html, all other libraries please place in side the corresponding folder.
ii. in web.config, you may change the maproute properties, you can map your view as default or add new map route.
Thank you.
This is an MVC 6/WebApi application. I'm attempting to use WebApi on the backend with AngularJS on the frontend.
I have two static files: index.html and login.html
(There will eventually be more static files.)
My Angular app is contained in the index.html while views (such as /login) are loaded from static files (i.e. login.html).
If I go to my root URL, index.html is loaded just fine. However, if I go to /login, I receive a 404 page not found.
Now, let it be said, I DO NOT want to bog down my application with a bunch of controllers and views as it's unnecessary to simply serve static files. That's overkill.
I have my routes setup to serve API calls (i.e. ~/api/whatever). How I get MVC 6 to ignore all other routes?
FYI, it also appears that MapPageRoute is deprecated in MVC 6?
EDIT:
One thing I've done to actually get it working is add my own middleware to intercept the request. The code below is added after all of my default middleware in the Configure method:
app.Use(next => async context =>
{
if (context.Request.Path.Value.StartsWith("/api"))
await next.Invoke(context);
else
await context.Response.WriteAsync(System.IO.File.ReadAllText("index.html"));
});
This seems a bit much and it's just a hack. All it does is allows any request that begins with "/api" to go through (which is then picked up by the MVC middleware), but any other call is served with the contents of the index.html. So, if my requested URL is "/login", the index.html file is served, then Angular looks at the route and loads the login.html file into view.
Any other suggestions?
Okay, so since something didn't exist in the MVC 6/ASP.NET 5 framework, I've created my own middleware that provides a lot more flexibility. It has been added to GitHub and is available through NuGet.
The project page is: https://github.com/a11smiles/AngularMiddleware
I was able do what you are asking here. Basically, I added a catch all route to my index action:
[Route("{*path}")]
meaning if no MVC action does not exist, call my Index action and angular routing will take from there
I'm developing a single page application using angularJs with a layout page that will be available for all my pages, but now I want some pages to be loaded without the layout page included in it, how can I do that. Any idea on this. Remember my pages are not #razor rendered with .cshtml except the layout and the index page all the other pages in my app are .html files.
Index.cshtml:
<div data-ng-view></div> - This is where all my pages will get loaded in to using the ngRoute
_Layout.cshtml:
<body>
<aside><nav>....</nav></aside>
<section><header>...</header>RenderBody()</section> - This is where my index page gets called
<aside>....</aside>
</body>
Now, I would like to get my page still loaded through the #index as my application is SPA, but _Layout.cshtml should be ignored.
Any *.cshtml pages are rendered server side and then served to the client.
*.html pages are statically served to the client.
Usually any static resources are put in the "Content" folder. In my own personal project this is where I put my static html pages.
In other words, you are in fact using Razor. In this case, using a different _layout.cshtml is answered in this stackoverflow question:
How do I specify different Layouts in the ASP.NET MVC 3 razor ViewStart file?
Also, usually, in general, for an SPA app, data is served asynchronously through a REST API or a REST/JSON API. In which case, once you're layout is loaded client side, you shouldn't have to deal with *.cshtml files, you should only have to deal with pure data and your javascript on the client side takes care of rendering that data into html.
In my personal project, I have a HomeController that serves a static html page:
public class HomeController : Controller
{
public ActionResult Index()
{
return Redirect(Url.Content("~/Content/index.html"));
}
}
What happens here is that when the user goes to http://localhost/ it executes the Index action from the HomeController which redirects to a static html file that contains my layout.
Any requests after that are loaded using Ajax requests that return JSON data. In other words, for any following requests, I don't have to deal with Razor "*.cshtml" files.
You shouldn't need to "ignore" _layout.cshtml since you're suppose to be serving just data.
I created an empty Web API project and have this:
GlobalConfiguration.Configure(WebApiConfig.Register);
When I create a non-empty Web API project I have this
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
RouteConfig.RegisterRoutes(RouteTable.Routes);
I do not need MVC Areas.
I do not need MVC filters.
I do not need Bundling/Minification as this will be handled my client side libraries.
I DO NEED (at first sight) the RouteConfig because I need the MVC HomeController which renders the initial _Layout_cshtml HTML file.
I am doing a Single Page App (AngularJS) + Web API.
Because of the last point above I have to add MVC stuff to my Web API Project.
Is there any possibility (angularJS/other JS libraries) on client side when the browser starts to initially retrieve a html file and render this instead of calling the MVC RenderBody() Method?
For a SPA with WebApi, you should not let MVC or .NET do anything to the static side of the site. That will just slow everything down and it's completely unnecessary. The words ".Net controller" and SPA should not be used together :)
The setup I use, when I want to test end-to-end with WebApi, is to have a static site in IIS, say mydomain that contains the entire contents of your static site, at least index.html. Then I create a subfolder under that site called "api" that is a full application. This will be your WebApi. Since it's a subfolder under mydomain CORS is no problem, but as far as IIS is concerned the root is pure static, and the "api" folder is a full-blown .Net application.
Here's what it looks like in IIS...
You could just embed the HTML file as a project resource and return it directly?
public class HomeController : ApiController
{
[HttpGet]
[Route("/")]
public HttpResponseMessage Get()
{
var content = new StreamContent(this.GetType().Assembly.GetManifestResourceStream(this.GetType(),"home.html"));
content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return new HttpResponseMessage() { Content = content };
}
}
Really all you need to do is setup a static HTML file wherever you keep your other static resources (scripts, css, etc).
You can then just redirect to it from your root controller:
public class HomeController : ApiController
{
[HttpGet]
[Route("/")]
public RedirectResult Get()
{
return Redirect("/contents/myapp.html");
}
}
My Angular app is splitted into several subapps. I'm working with laravel which is also responsible for the routing between the subapps.
So there are the following urls handled by laravel:
ModuleX: /moduleX
ModuleY: /moduleY
ModuleZ, Item n: /moduleZ/item-n (unlimited amount of items)
And finally on top of these there are my 3 Angular subapps.
So for example: /moduleZ/item-1/#/hello/world
Additionally the templates, partials and a RESTful API are served by laravel under the following urls:
/templates
/partials
/api
If I set the base url with the html tag <base href="http://www.example.com/app/"> I can use relative urls for templates, partials and the api but not for the routing. I'll allways have to add the module url part like that moduleX/#/hello/world.
If I set the base url like for example <base href="http://www.example.com/app/moduleX/"> I can write all links like #/hello/world but the templates, partials and api requests aren't working anymore.
The whole app also sits in a subfolder so I can't just use for example /templates.
So basically my problem or the question now is, what's the best way for handling the different base urls? I don't really like it to prepend the module name to every link.
Look it's might be a particular solution, but may be you should use filters for urls?
For example:
.filter('routeFilter', [function () {
return function (route) {
if (some condition mean this direct html link){
return 'MODULE-X/' + route;
}else{
return route
}
};
}])
I would suggest you let (sub-)apps know their real base not the parent's one, but you make the server responsible for climbing the path hierarchy to find higher level shared resources for missing local ones. This also makes it very easy to prototype new sub-apps, test changes to common pieces independently first, etc.
In a webserver like Apache, this would look like a rewrite rule (conditional on not finding a file) it just substitutes the same file in the parent hierarchy.
In laravel (according to the router docs) it looks like you can add optional 'directories' to your current rules, i.e.:
Route::get('/.../app/templates/{name}', function($name)
...
becomes:
Route::get('/.../app/{module?}/{item?}/templates/{name}', function($name, $module, $item)
...
You could then use $module and $item if you need to test a resource change with specific sub-app/items.
The drawback in making the server responsible for handling inheritance is the independent client fetch/cache of identical resources with different paths. But you can at least choose between large file inefficiency or access latency by using either rewrites or redirects. You can also always hardcode significant paths in production clients later and still benefit from having a hierarchy for testing and graceful handling of occasional errors in client side links.
You can do it in a simpler way if you use combination of service and directive.
You can implement a directive similar to ngHref which when given a link will transform it and append the given link back. It will be injected with a service which will give it the base url or relative url or anything module specific.
This service which is injected in directive will be configured using serviceProvider in app.config block of each sub-app. Since angular injector have only one instance of each service I think you will need more than one injector or one injector per sub-app. Its unclear whether they share injector among them in your app.
You can configure each service according to module to return different base paths. Which will be appended by directive to each link every time.
With this you can use <base href="http://www.example.com/app/"> and that should solve your problem.
I haven't written any code but I can help if you need it.