I am using VS 2015 RC, working on a WebAPI project and when I try to use the routing in Angular 2 I get the following errors:
Failed to load resource: the server responded with a status of 404 (Not Found) localhost:14580/angular2/router
Potentially unhandled rejection [3] Error loading "angular2/router" at localhost:14580/angular2/router
Error loading "angular2/router" from "Components/main/main" at localhost:14580/Components/main/main.js
Not Found: localhost:14580/angular2/router (WARNING: non-Error used)
The view is the basic import of the main.ts component. The component code is as follows:
/// <reference path="../../Scripts/typings/angular2/angular2.d.ts" />
/// <reference path="../../Scripts/typings/_custom/ng2.d.ts" />
import {Router, RouteConfig, RouterLink, RouterOutlet} from 'angular2/router';
import {Component, View, bootstrap} from 'angular2/angular2';
import {Login} from '../login/login';
import {status, json} from 'Scripts/utils/fetch'
// Annotation section
#Component({
selector: 'my-app'
})
#View({
templateUrl: 'Views/main/main.html',
directives: [RouterLink, RouterOutlet]
})
#RouteConfig([
{ path: '/login', as: 'login', component: Login }
])
// Component controller
export class Main {
//router: Router;
name: string;
constructor(router: Router) {
//this.router = router;
this.name = 'Routing';
router.config([{ path: '/login', as: 'login', component: Login }]);
}
login(event, email, password) {
event.preventDefault();
window.fetch('/api/Account/Login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email, password
})
})
.then(status)
.then(json)
.then((response) => {
alert(response);
// this.router.parent.navigate('/home');
})
.catch((error) => {
alert(error.message);
console.log(error.message);
});
}
}
bootstrap(
Main
);
You need to include router.dev.js on your html in the same way you included angular2.dev.js. So simply add this line to your index.html's head:
<script src="../node_modules/angular2/bundles/router.dev.js"></script>
PS. I know you already solved this, but the answer was not clear and I took a while to realize what was wrong with my app.
If you bring in the latest definitelyTyped typings for Angular 2 it may be easier to get it working.
Here is a working example:
http://www.syntaxsuccess.com/viewarticle/routing-in-angular-2.0
Related
It's my first time building a web api. I've successfully set up the model view controller and enabled token generation. However, I am stuck on how to pass the access token through the request header. After I have logged in and attempt to view another page, there is nothing in the header in regards to the authorization therefore I receive a 401 error. I've looked at several blogs, forums and articles over the past couple days and cannot come to a conclusion on how this is done. I have my jquery storing the header in a variable, but I am unsure on where that is stored and how to reference it or where to put the reference. I've messed around with setting it in global.asax and some of the config files, also at the top of the controller class. My next thought is to create a web page for each controller and storing the authorization there, even still I don't know how to dynamically place a token that would vary for other users. I feel like there is something very simple that I'm missing. I suppose my question is how do I store my javascript variable in each request header? Here is my javascript for reference:
$("#btnLogin").on('click', function () {
//var data = { Email: $("#loginEmail").val().trim(), Password: $("#textPwd").val().trim(), ConfirmPassword: $("#loginPwd").val().trim() };
$.ajax(
{
url: "/TOKEN",
type: "POST",
data: $.param({ grant_type: 'password', username: $("#loginEmail").val(), password: $("#loginPwd").val() }),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
success: function (resp) {
sessionStorage.setItem('userName', resp.userName);
sessionStorage.setItem('accessToken', resp.access_token);
var authHeaders = {};
authHeaders.Authorization = 'Bearer ' + resp.access_token;
$.ajax({
url: "https://localhost:44327/api/values",
type: "GET",
headers: authHeaders,
success: function (response) {
$("#loginEmail").val(),
$("#loginPwd").val(),
$("#msg").text(response)
}
});
},
error: function () {
$("#msg").text("Authentication failed");
}
})
});
In my .net core razor page project, i would like to call server side methods from a cshtml input without reloading the page. I'm still a newbie with razor pages.
.cshtml :
input type="submit" id="AddCart" asp-page-handler="AddToCart" hidden
Some JS to .click() the input.
.cs :
public async void OnPostAddToCart()
{
//code
}
So far i did not find a way to prevent the page reload and still access my server-side methods.
Thanks
EDIT :
Looking at the link provided by brad, i managed to make it work.
I added #Page "{handler?}" to write the url without the handler (not sure if it matters for ajax),
I set my ajax url to "thePage/theMethod",
I decorated my razor controller class with [ValidateAntiForgeryToken]
And mentioned the anti forgery token in ajax :
$.ajax({
url: "/mainPage/AddToCart",
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
alert("success");
},
complete: function () {
alert("complete")
},
failure: function () {
alert("failure");
}
});
First ,change the naming of your Handler method like below :
public async void OnPostAddToCartAsync()
{
//code
}
Refer to Handler Methods in Razor Pages for more details on the nameing convention .
Second ,If you want to use ajax in Razor Pages , the URL pattern should be like "/mainPage?handler=AddToCart" .One thing to note down is, Razor Pages are designed to be protected from (CSRF/XSRF) attacks. Hence, Antiforgery token generation and validation are automatically included in Razor Pages. I believe that is the problem here. Your page may have antiforgery token present on the page if you have form tag in your HTML. But you need to pass the same in your Ajax request.
Add antiforgery token using #Html.AntiForgeryToken(), if not
present.
Modify your Ajax request to send the same in request header like
below:
<input type="button" id="AddCart" onclick="clickbtn()" value="Submit"/>
function clickbtn() {
$.ajax({
url: "/Test?handler=AddToCart",
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function ()
{
alert("success");
},
complete: function ()
{
alert("complete")
},
failure: function ()
{
alert("failure");
}
});
}
Since the script sends the token in a header called X-XSRF-TOKEN,
configure the antiforgery service to look for the X-XSRF-TOKEN
header:
services.AddAntiforgery(option => option.HeaderName = "X-XSRF-TOKEN");
Read this post Handle Ajax Requests in ASP.NET Core Razor Pages to know more about making ajax request with ASP.NET Core razor pages.
If you do not want to reload the page you must use ajax or XMLHttpRequest , (the former being based on the latter).
<script>
window.onload=function()
{
window.click=function()
{
$.ajax({
url: '[baseUrl/OnPostAddToCart]',
data: JSON.stringify(postData), //your data
type: 'POST',
contentType: 'application/json',
dataType: 'json',
success: function (result) {
alert(result); //do something if successful
},
complete: function(){
//do something on complete
},
failure: function (err) {
alert(err); // Display error message
}
});
}
}
</script>
<input onclick="click()" type="button"/>
Using XMLHttpRequest:
window.click=function()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "[Your URL]");
xhr.onload=function()
{
if(xhr.status==200)
resolve(xhr.response);
else
reject("error:"+xhr.status);
}
var data=JSON.stringify({some_data});
xhr.send(data);
}
Controller method
public class MyController:Controller
{
[HttPost]
[Route("/OnPostAddToCart")]
public async Task AddToCart(object data)
{
}
}
P.S For more information on ajax
I am trying to upload an image to a server with Axios, but having Error 400 "Bad Request".
I have tried many different ways to implement it: explicitly specifying a "Content-Type", changing controller, trying $.ajax, etc. from Google.
A brief description of what I am expecting: I choose an image as suggested by <input/> and once I submit my choice it is sent to the server.
Currently, in my controller, I set a breakpoint, however, I've never seen request entering it.
My stack is Asp.Core WebAPI + React.js + Axios.
I have stopped on the following code:
Controller:
[Route("api/char")]
[ApiController]
public class CharacterController : ControllerBase
{
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> SetProfilePhoto(IFormFile file)
{
return Ok();
}
}
React Component:
export default class BioEdit extends React.Component {
...
changePhoto = event => {
event.preventDefault();
const file = event.target.files[0];
const formData = new FormData();
formData.append("File", file);
Axios.post("api/char/SetProfilePhoto", formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
.catch(error => console.log(error));
}
render(){
return (
<label >
<img src={this.state.char.image} width="30%" height="30%" className="border border-secondary" />
<input type="file" style={{ display: "none" }} accept="image/*" onChange={this.changePhoto} />
</label>
);
}
}
Here is what I have in the browser (Yandex browser it is to be specific, based on Chrome):
There are two options based on whether you need API Controller or not.
The first is to remove the APIControllerAttribute from off your controller, then nothing else is needed to be done;
The second is to set up the Startup.cs as doc prescribes. Adding
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); solved my problem.
NOTE: it is not necessary to set up headers to undefined or whatever. Axios deals with it in the right way itself.
add undefined content type. it should work then
Axios.post("api/char/SetProfilePhoto", formData, {
headers: { 'Content-Type': undefined }
})
Hello i have build ajax that call my function in Control.
this project in Orchard(new in that) it is like mvc as i know.
I have problem with url/path to the function.
if i use url: '#Url.Action("GetFilesList", "FileUpload")' NOT working
I know that in '#Url.Action first value is my function name , and secont is my controller name(without controller it self)
but like that with direct url to function it is working
'http://localhost:30321/OrchardLocal/VnModule.Module/FileUpload/GetFilesList'
This my code:
Work:
$.ajax({
url: 'http://localhost:30321/OrchardLocal/VnModule.Module/FileUpload/GetFilesList',
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function () {
}
});
And this is not working:
$.ajax({
url:'#Url.Action("GetFilesList", "FileUpload")',
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function (xhr) {
}
});
My controller:
namespace VnModule.Module.Controllers
{
public class FileUploadController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("GetFilesList")]
public void GetFilesList(string sNum)
{
int myNumber = Int32.Parse(sNum);
}
}
}
Sow i sure that problem is in url: '#Url.Action("GetFilesList", "FileUpload")' but i cant understand what i am doing wrong.
Do you have any ideas?
Orchard Documentation link about module
Every module in Orchard CMS is an area of ASP.NET MVC project. So You need to add area attribute in your code like as:
url: '#Url.Action("GetFilesList", "FileUpload", new{area = "module name here"})'
This way your problem should be solved.
Check your URL in network panel and identified which URL is called in ajax request It's help you a lot to find a solution and as per orchard if it is required to pass area then change #Url.Action accordingly.
I found the solution how to see the url ( Url.Action razor) , in external js file;
i have added data-id with this path to my button like this:
<input type="submit" value="Savee" id="btn_UploadImg" onclick="btn_Upload_Click(this)" data-urlaction="#Url.Action("GetFilesList", "FileUpload", new { area = "VnModule.Module" })" />
And to get this Url Action path in external js file you can like this:
var funcUrl = $("#btn_UploadImg").data("urlaction");
$.ajax({
url: funcUrl,
type: 'POST',
data: {
sNum: "123",
__RequestVerificationToken: token
},
success: function () {
},
error: function (xhr) {
alert("Error:"+xhr.responseText);
console.log(xhr.responseText);
console.info(xhr);
}
});
Hi I am calling my API using below code
$http.get('/api/controller/method?param=value').
then(function (response) {
if (response.status == 200) {
console.log(response.data);
}
});
It is working fine in my local machine (http://localhost/api/controller/method?param=value).
But when I deployed it in server with application name app, it is not able to call the API(http://server-ip/app/api/controller/method?param=value).
Obviously, it won't, as URL are different. So what is the correct way to call an API in c# so that it will work in any server.
What I have tried:
1. URL.Action : It is not working in this case.
2. I don't want to Use #HTML.hidden
3. Call starting with or without slash (/)
I usually solve this by using a factory like this -
First in the .cshtml page I load all the angular js required.
Then create a factory for the baseURL like this -
function(angular){
var module = angular.module('NameOfMyModule'); //gt the module
module.factory('BaseUrl', function(){
return '#Url.Action("Action", "Controller")';
});
}(window.angular);
Then inject that BaseURL inside the controller -
....
module.controller('SomeController', [...., 'BaseUrl', function(...., BaseUrl){
$scope.baseUrl = BaseUrl;
}]);
....`
Finally prepend it in the url
$http.get($scope.baseUrl + /...../).then(....);
I'm not sure if I undestood your question correctly, but I'm using angular constant to set server url
angular.constant("CONSTS", {
"DEV_URL": "http://localhost:12345",
"LIVE_URL": "http://server-ip/app"
})
and then in $http call
$http.get(CONSTS.DEV_URL + '/api/controller/method?param=value').
then(function (response) {
if (response.status == 200) {
console.log(response.data);
}
});
I'm sure there is a way to automate this (gulp, grunt), but I didn't get there yet.
When deploying the app I would just manually change the constant.
If I'll find outomatic way to it I'll update the answer.
Hope this helps a bit...
I don't know your build process etc. but usually you can store application path in some constant value in Angular and use it when calling your API as a prefix.
If you have some kind of automated build, it is easy to prepare deployment packages with changed values(by using Gulp/Grunt/TeamCity/Octopus, whatever you like).
//controller
app.controller("sampleController", function($scope, commonService) {
//post
$scope.postData = function() {
var command = {}
commonService.postSample(command);
}
//get
commonService.getSample().then(function(data) {
$scope.permissionList = data;
});
});
//service
app.service('commonService', function($http, $q) {
this.postSample = function(command) {
var deferred = $q.defer();
$http({
method: 'POST',
data: command,
url: '/Attendance/CreatePersonDailyLeave'
})
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
deferred.reject(data);
});
return deferred.promise;
}
this.getSample = function(id) {
var deferred = $q.defer();
$http({
method: 'GET',
async: true,
url: '/Attendance/GetRoles?id=' + id
})
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
deferred.reject(data);
});
return deferred.promise;
}
});