I'm trying to get the URL parameters into my component to search using an externsre service. I read I can use angular2 routes and get params using RouteParams but I don't think that's what I need because the first page of my angular application is a Razor view.
I'll try to explain better.
My URL looks like:
http://dev.local/listing/?city=melbourne
I'm loading my root component in a razor view with something like:
<house-list city = "#Request.Params["city"]"></house-list>
then on my root component I have:
export class AppComponent implements OnInit {
constructor(private _cityService: CityService) { }
response: any;
#Input() city: any;
ngOnInit() {
this.getHouses();
}
getHouses() {
this.__cityService.getHousesByCity(this.city)
.subscribe(data => this.response = data);
}
}
So I was expecting that the 'city' in my component gets the string passed from the razor view but it's undefined.
What am I doing wrong? Is there a way of getting the params without using the routing? If not, what is the right way of using razor?
Angular doesn't provide special support for this. You can use How can I get query string values in JavaScript?
From what I have seen Location is planned to be reworked to provide support for get query params even without using the router.
Related
My GET method WORKS fine when I use the url logged in as SuperUser like this(I get the name of the first user pulled from the DB):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/GetMessage
But I cannot access the POST method in the same controller either using AJAX from view or just by entering the url (post method doesnt get hit/found):
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage
And also this fails as well:
$('#sendChat').click(function (e) {
e.preventDefault();
var user = '#Model.CurrentUserInfo.DisplayName';
var message = $('#chatBoxReplyArea').val();
var url = '/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage';
$.post(url, { user: user, message: message }, function (data) {
}).done(function () {
});
});
The Error message is:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage'.
</Message>
<MessageDetail>
No action was found on the controller 'ChatApi' that matches the name 'SendMessage'.
</MessageDetail>
</Error>
And sometimes:
"The controller does not support GET method"
even though I do have both a GET and a POST there and the GET works. What am I missing?
I have made a routing class in my DNN project:
using DotNetNuke.Web.Api;
namespace AAAA.MyChatServer
{
public class RouteMapper : IServiceRouteMapper
{
public void RegisterRoutes(IMapRoute mapRouteManager)
{
mapRouteManager.MapHttpRoute("MyChatServer", "default", "{controller}/{action}", new[] { "AAAA.MyChatServer.Services" });
}
}
}
I added a DNN Api Controller in folder Services of my project named AAAA.MyChatServer:
using DotNetNuke.Web.Api;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
namespace AAAA.MyChatServer.Services
{
[DnnAuthorize(StaticRoles = "SuperUser")]
public class ChatApiController : DnnApiController
{
[HttpGet]
public HttpResponseMessage GetMessage()
{
ChatServerManager csm = new ChatServerManager();
var users = csm.GetAllUsers();
var user = users.FirstOrDefault().Name;
return Request.CreateResponse(System.Net.HttpStatusCode.OK, user);
}
[System.Web.Http.HttpPost]
public HttpResponseMessage SendMessage(string toUser, string message)
{
return Request.CreateResponse(System.Net.HttpStatusCode.OK);
}
}
}
There are two ways to call a POST method in a DNN WebAPI: with parameters and with an object. If you use parameters, as you have in your SendMessage method, those parameter values need to be delivered via the Query String.
On the other hand, creating an object and sending that with your call to the WebAPI method can handle a great many more scenarios and is arguably a better way of handling any POST method (as it hides those values from prying eyes, making the call more difficult to counterfeit). To handle this, you can remove the parameters from your SendMessage method and instead interrogate the HttpContext.Current.Request object within your method. The object you created { user: user, message: message } will be nestled in there somewhere.
As it is written in your example, your object was sailing past your parameters like two ships in the night.
I've only just figured this out myself, and I don't have all the understanding I need yet, but hopefully this will help you along your way. Here are some articles I referenced in my quest to use cURL to upload a file to my DNN WebAPI:
https://www.dnnsoftware.com/community-blog/cid/134676/getting-started-with-dotnetnuke-services-framework
https://www.dnnsoftware.com/community-blog/cid/144400/webapi-tips
How To Accept a File POST
https://forums.asp.net/t/2104884.aspx?Uploading+a+file+using+webapi+C+
https://talkdotnet.wordpress.com/2014/03/18/dotnetnuke-webapi-helloworld-example-part-one/comment-page-1/
http://dnnmodule.com/Article/ArticleDetail/tabid/111/ArticleId/511/Dotnetnuke-7-0-WebAPI-Tips.aspx
How to post file using Curl in WebApi in Asp.Net MVC
Good luck!
Your Web Api for SendMessage contain 2 parameter, so it should POST in query string :
http://localhost/DesktopModules/AAAA_MyChatServer/API/ChatApi/SendMessage?touser=john&message=hello
if you want to POST it using data of object, you need to make the Web Service parameter as object model
Also your javascript parameter is different from the Web Service, as it use "toUser"
I'm attempting to implement a RESTful API using Grails 2.5.5, and I'm running into a few issues.
It appears that Grails does not automatically map any methods for the corresponding HTTP methods, so I'm editing UrlMappings.groovy.
For example, take the following URLs:
GET /v1/1/persons/ <--- List of persons
POST /v1/1/persons/ <--- Create a new person
PUT /v1/1/persons/1234 <--- Edit person with ID of 1234
These are my url mappings:
"/v1/$appId/$controller/$action?/$id?(.$format)?" {
namespace = "v1"
}
"/v1/$appId/$controller"(action: "save", method: "POST") {
namespace = "v1"
}
"/v1/$appId/$controller/$id"(action: "update", method: "PUT") {
namespace = "v1"
}
So now, the first mapping will handle the GET request in my example urls as well as other generic urls.
The second mapping will handle the second url from my example urls.
And lastly, the third mapping handles the third url from my example urls.
The issue I'm facing now is that my command object isn't getting bound properly for my PUT request. The POST request works fine however.
These are my methods:
def save(MyCommand cmd) {
// works great
}
def update(MyCommand cmd) {
// cmd properties are null
// params.id is bound though. So I'm getting the path variable.
}
As you can see, the logic is very simple.
But I'm completely stumped as to why I can't get the request body in the PUT method.
Additional question: How can I get the above urls to work in addition to this url?:
/v1/1/persons/1234/status
I tried the following mapping, but it does not seem to work:
"/v1/$appId/$controller/$id/$action" {
namespace = "v1"
}
It feels like I'm stuck in this URLMappings hell!
I could use some help, figure out how to pass model data from mvc application to a angular2 component running inside mvc.
Lets say I have a cs.html file that has an component
<my-app></my-app>
This will load the angular2 component. I need to generate some binding to keep mvc models intact with my angular2 models.
First of all, I'm trying to pass a model to the component via the Input property.
CSHTML file:
In the top of my cshtml file, I have:
#model MainModel
<script>
var model = #Html.Json(Model.Form.PassengerModel);
</script>
I want to pass this model to my angular2 component.
What I have tried are:
<my-app passengerModel="model"></my-app>
Angular2 component:
import { Component, Input } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './Content/Scripts/angular2components/app.component.html',
})
export class AppComponent {
#Input() passengerModel: PassengerModel;
constructor() {
console.log("Model loaded?: " + this.passengerModel);
}
}
export class PassengerModel {
constructor(
public Adults: number,
public Children: number
) { }
}
The problem is that the model is undefined always. Is there any way to pass a model in to the component?
The problem you have outlined above is that your binding is not correct for the context you are attempting to use it in.
<my-app passengerModel="model"></my-app>
The above line is telling Angular to bind passengerModel inside your my-app component to a property on the host component named model. This means the page (component) which hosts your my-app component should be a component with a property named model. You have created a global variable which is not in the scope of your host component. Angular2 specifically isolates the scope of each component so that you do not accidentally introduce unwanted side effects.
Save yourself some pain an anguish and embrace Angular fully. Ditching your MVC Page Controllers and moving to WebApi service calls will yield better results and save you the need to translate the model manually among other issues you will run into going down the mixed route.
Considerations:
#Html.Json will ultimately cause your data to be exposed directly in your script tag. This could be a security risk if the data is sensitive and if you start using MVC Model bindings in the page alongside Angular bindings they will fight each other.
Basically these approaches are diametrically opposed as ASP.NET MVC is a server side approach and Angular is a client side approach. Mixing them in the same application will always be awkward at best.
WebApi gives you the JSON serialization more or less for free. Your MVC model is automatically serialized to JSON by the framework when returning an HttpAction. If you are trying to avoid converting your ASP.NET MVC views to Angular Components then I understand. You may not have a choice but if you do I would steer clear of mixing these two.
[HttpGet]
[AcceptVerbs["GET"]
[Route("passengers/{id:int}")]
public IHttpActionResult GetPassenger(int id)
{
// For illistration...
try
{
var passengerModel = PassengerService.LoadPassenger(id);
return Ok(passenger);
}
catch(Exception e)
{
return InternalServerError(e);
}
}
https://angular.io/docs/ts/latest/tutorial/toh-pt6.html
// I would normally put this in the environemnt class..
private passengerUrl = 'api/passengers'; // URL to web api
constructor(private http: Http) { }
getPassenger(id: number): Promise<Passenger> {
return this.http.get(`this.passengerUrl/${id}`)
.toPromise()
.then(response => response.json() as Passenger)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
I'm currently working on an ASP.NET MVC project to which some AngularJS was added - including some AngularJS directives.
I need to add to an AngularJS directive a MVC partial view. Obviously,
#Html.Partial("_PartialView", {{name}})
doesn't work.
So far all my searches online provided no help.
Any idea how I could render a partial view inside an Angular directive?
Thanks!
Angular exists strictly on the client side whereas MVC views exist on the server side. These two cannot interact directly. However, you could create an endpoint in which your partial view is returned as HTML. Angular could call this endpoint, retrieve the HTML, and then include it inside a directive.
Something like this:
app.directive("specialView", function($http) {
return {
link: function(scope, element) {
$http.get("/views/partials/special-view") // immediately call to retrieve partial
.success(function(data) {
element.html(data); // replace insides of this element with response
});
}
};
});
app.directive("myDirective", ['', function () {
return {
restrict: 'A',
scope: {
foo: '='
},
templateUrl: '/home/_myDirectivePartialView',
}]
} }]);
Just need to use templareURL and specify the route to get the partial view.
Ok. I have a url setup to log a user out. On the server, there is no html. The session on the server simply gets destroyed, and then the user is redirected to an address.
This works fine with plain html, but with Angular i am having issues. I've been routing all main routes using $routeProvider.when('/foo', {templateUrl: '/foo.html', controller: 'Ctrl'}) and that works fine for normal templated routes.. however, if there is no template it will not work.
So, how do i support the route /logout in the same fashion as above, when there is no html template?
A workaround is to use template instead of templateUrl. From the Angular docs:
template – {string=} – html template as a string that should be used
by ngView or ngInclude directives. this property takes precedence over
templateUrl.
This can be used as follows:
$routeProvider.when("/foo", {template: " ", controller: "Ctrl"});
Note: You must use " " instead of an empty string "" because Angular uses an if (template) check before firing the controller, and an empty string evaluates to false.
-- EDIT --
A better way to do it is to use the resolve map. See the Angular Docs:
resolve - {Object.=} - An optional map of
dependencies which should be injected into the controller.
This can be used like this:
$routeProvider.when('/foo', {resolve: {redirect: 'RedirectService'}});
Note: I've changed it from "Ctrl" to "RedirectService", because what you're describing in the question isn't really a "controller" in the Angular sense. It doesn't set up scope for a view. Instead, it's more like a service, which ends up redirecting.
I am writing the solution based on the already accepted answer and the github issue mentioned in it's comments.
The approach I am using is a resolve parameter in the $routeProvider. In my case I was trying to create a nice solution to logout in my application, when user goes to /logout.
Example code of $routeProvider:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
...
when('/logout', {
resolve: {
logout: ['logoutService', function (logoutService) {
logoutService();
}]
},
}).
...
}]);
In the resolve part you specify a service (factory) by name and later on you have to call it. Still it is the nicest solution around.
To make the example complete I present my logoutService:
angular.module('xxx').factory('logoutService', function ($location, Auth) {
return function () {
Auth.setUser(undefined);
$location.path('/');
}
});
Works great!