Angular API Call doesn't get called - javascript

Here is my code. I'm trying to display a list when a property is selected from a combobox. I'm getting the list from backend, but I get this error whenever I click the display button. Even though, the method is a GET method. What could be the problem?
TS:
filter() {
this._stockService
.getWarehouseTransferReport()
.subscribe((response: any) => {
this.dataSource = new MatTableDataSource(response);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.dataSource.filterPredicate = (data, filter) =>
this.filterPredicate(data, filter);
});
}
filterPredicate(data: IWarehouseTransferItem, filter: string) {
let searchText = data.Reference;
if (data.Reference) {
searchText += (data.Reference as any).toLocaleLowerCase("tr");
}
if (data.DeliveryNote) {
searchText += (data.DeliveryNote as any).toLocaleLowerCase("tr");
}
if (data.StockIntegrationCode ) {
searchText += (data.StockIntegrationCode as any).toLocaleLowerCase("tr");
}
if (data.Product.ProductName) {
searchText += (data.Product.ProductName as any).toLocaleLowerCase("tr");
}
return searchText.indexOf(filter) >= 0;
}
Service TS:
getWarehouseTransferReport(): Observable<IWarehouseTransferItem[]> {
return this._http.get("Stock/GetWarehouseTransferReport");
}
Backend C#:
/// <summary>
/// TRANSFER REPORT
/// </summary>
/// <param name="producdId"></param>
/// <returns></returns>
[HttpGet]
public List<DtoWarehouseTransferItem> GetWarehouseTransferReport(int producdId)
{
return WarehouseSpProvider.GetWarehouseTransferReport(producdId);
}
}

It probably means that server know the method but the target source is not supported. Here is the reference Mozilla link.
So basically it is not Angular Http client problem to be precise.
Reference link which shows many details on 405 status code problem. Link

Your C# Backend code requires a parameter int productId but I think you are not passing any parameter that's why it is now being called.

May be you are passing wrong object or object mismatches the value.
may be datatype issue or parameter count issue and your API needs
proper object and value.

Related

Problems when trying to get datasnapshot into the class i want

I'm trying to retrieve the data sent from my android app that is formed like this.
I'm trying to do it on JavaScript. I originally did this on Java and it was something like this
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Chat chat = postSnapshot.getValue(Chat.class);
I want to do the same thing on JavaScript but failed when I'm trying to. What I have now is this
class Chat{
constructor(detail,file_name,is_phone,type,user_id){
this.detail = detail;
this.file_name = file_name;
this.is_phone = is_phone;
this.type = type;
this.user_id = user_id;
}
detail(){ return this.detail;}
file_name(){ return this.file_name;}
is_phone(){ return this.is_phone;}
type(){ return this.type;}
user_id(){ return this.user_id;}
}
//Sync obj changes
dbRefObj.on('child_added',snap => {
myChat = new Chat (snap.val());
console.log(myChat);
});
But what I got is everything being set to detail...
The issue here seems to be that you want to spread the values, instead you're just assigning to the first parameter:
In the current implementation snap.val() is assigned to the detail param
class Chat{
constructor(detail, file_name, is_phone, type, user_id){
// ...
}
}
The following implementation will take the corresponding values from inside the snap.val()
class Chat{
constructor({ detail, file_name, is_phone, type, user_id}) {
// The difference is the use of the deconstructive syntax
}
}

How to return data from cloud function to android and use it?

How can I get data from Cloud onCall() function to Android client and use it in a java code?
The client connects to function and function connects to firestore. But I can`t get data back from the function to client. I know that data has json format. But how to pass data to android, and how to use this data in android code (for example to setText in TextView).
java onClick() method:
onClick(){
String first = editTextTitle.getText().toString();
String second = editTextDescription.getText().toString();
//Here I try to setText received from function, but nothing happen.
tv_function.setText(function_3(first, second).toString());
}
java - call function:
private Task<String> function_3(String first, String second) {
mFunctions = FirebaseFunctions.getInstance();
Map<String, Object> data = new HashMap<>();
data.put("text", first);
data.put("push", second);
return mFunctions
.getHttpsCallable("sendMessageToAndroid")
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>()
{
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws
Exception {
String result = (String)task.getResult().getData();
return result;
}
});
}
javaScript function:
exports.sendMessageToAndroid = functions.https.onCall((data, context) => {
var batono = {
first: data.fara,
second: data.mina
}
return db.collection('abra-codabra').doc("mu-mu").set(batono)
.then(()=>{
var arba = {
aram:"aramando",
borem:"boremuno"
}
return arba;
});
});
How to get var "arba" to AndroidStudio and set it to TextView?
By doing
Map<String, Object> data = new HashMap<>();
data.put("text", first);
data.put("push", second);
return mFunctions
.getHttpsCallable("sendMessageToAndroid")
.call(data)
...
(as shown in the example from the documentation) you send to your Callable Cloud Function a map with a text element.
However, in your Cloud Function code you do:
var batono = {
first: data.fara,
second: data.mina
}
So, it means that you should send a map with the following elements: fara and mina, not a map with text (or you would have done something like var batono = {text: data.text}).
So, you should most probably do something like the following (not tested however):
Map<String, Object> data = new HashMap<>();
data.put("fara", .....);
data.put("mina", .....);
data.put("push", true);
return mFunctions
.getHttpsCallable("sendMessageToAndroid")
.call(data)
...

can't retrieve data from async call

I am using ngx-translate service for translations in my angular app. I would like to create method that would accept path to string which needs to be returned. My method looks like this:
public translateString(parameter: string): string {
let message = "";
this.translate.get(parameter).subscribe((response) => {
message = response;
});
return message;
}
But it always returns empty string, I think the problem is the subscribe call so return message gets executed before message = response. Any solutions?
The data is not synchronously available. You'll need to return the observable, and then the caller can subscribe to do what they need to do once the message is available.
public translateString(parameter: string): Observable<String> {
return this.translate.get(parameter);
}
// and then used like this:
SomeService.translateString('hello world')
.subscribe(message => {
console.log(message);
})
use instant
It not require any observables.
this.message = this.translate.instant('Language')
You need to return your message inside subscribe.Like this:
public translateString(parameter: string): string {
let message = "";
this.translate.get(parameter).subscribe((response) => {
message = response;
return message;
});
}

Web API post parameter

I currently have an issue with a webapi call. I want to download and open a logfile with my ApiController.
I use a javascript function to post a filename to my controller.
Here is a helper function to post the parameter (answer from dystroy):
How to replace window.open(...) with a POST
Now when I use a simple string as parameter in my controller I can’t get the parameter, it is always null.
public HttpResponseMessage PostDownloadLogFile([FromBody]string psFileName)
{
//psFileName is always null
But if I use HttpReqeustMessage as parameter and read the form data from my request it is no problem and it works.
public HttpResponseMessage PostDownloadLogFile(HttpRequestMessage poRequest)
{
var loFormData = poRequest.Content.ReadAsFormDataAsync().Result;
string psFileName = loFormData["psFileName"]; //psFileName is set correct
Is there a solution to get the parameter with a simple parameter in my controller?
Update
This is my javascript helper function:
var loOpenWindow = function (psMethode, psUrl, poData, psTarget) {
var loForm = document.createElement("form");
loForm.action = psUrl;
loForm.method = psMethode;
loForm.target = psTarget || "_self";
if (poData) {
for (var lsKey in poData) {
var loInput = document.createElement("textarea");
loInput.name = lsKey;
loInput.value = typeof poData[lsKey] === "object" ? JSON.stringify(poData[lsKey]) : poData[lsKey];
loForm.appendChild(loInput);
}
}
loForm.style.display = "none";
document.body.appendChild(loForm);
loForm.submit();
};
Call it:
helper.openWindow("POST", apiRoutes.URLS.ApiPostDownloadLogFile, { "psFilename": $scope.data.showLogEntry.FullName });
There should be no problem from the client side code, because the controller methode with HttpReqeustMessage works without problems.
Here is the browser request:
Probably the problem is in your client code sending the data.
[FromBody] parameters must be encoded as =value
then, this does not work:
// Value will be null.
$.post('api/values', value);
// Value will be null.
$.post('api/values', { key: value });
But this work:
$.post('api/values', "=" + value);
Try to change your client code to send just =/path/to/your/file in the body.
Reference: http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
Ok I found a solution.
If I use a class as parameter and a property with the given name, it seems to work.
public class Param
{
public string psFileName { get; set; }
}
And
public HttpResponseMessage PostDownloadLogFile(Param poParam)
{
string psFileName = poParam.psFileName; //psFileName is set correct
This is not really a simple parameter but I can live with this solution.

Displaying Errors and Exceptions in Toastr, or similar method using MVC4, and Entity Framework

I'm trying to find a way to use Toastr to display errors to users as Exceptions or Errors occur within my application. The problems I'm running into seem to suggest that it would not be possible to have an exception that occurs in the Controller, or Data Access layer displayed in the current view using Toastr.
I'm wondering if any of you have run into this scenario and what your solution to it was?
What I'm trying to accomplish is that any time there is an unhandled exception, or someone handles an exception manually that we have the ability to display the error to the user without disrupting workflow. Toastr was suggested to me, but being completely javascript I'm not sure the best way to implement it within my MVC4 application.
One option I'm exploring is setting up my default index controller to handle an incoming error string so that I can redirect to it from the Application_Error method in the Global.asax.cs in order to give a friendly redirect, and then if that incoming string is not null then I can use toastr on the Index view. However this is not ideal because it requires a redirect, and disrupts workflow. Also it will not allow for me to display an error without having to thrown an exception or do all my error handling within the javascript.
Other important information is that we are using Telerik Kendo UI, and Razor Syntax if that would help me in any way.
For those of you who have this same question that I had here is the solution:
I found the first step of my solution here: https://github.com/martijnboland/MvcNotification
He had implemented his own form of Notification. But I wanted to be able to use Toastr, or any other kind of Notification options that were out there.
NOTE: Anywhere you see a class that ends in "Res" it's a resource file. This is to keep our strings in our application more organized. That way nobody gets mixed up with that.
Here is how I implemented my solution. NOTE: This works with MVC5 as well
First thing to do is the create a Toastr object in your source code. This will be used to pop the message to the user in the UI eventually.
public class Toast
{
public string type { get; set; }
public string message { get; set; }
public string title { get; set; }
public string positionClass { get; set; }
public int fadeIn { get; set; }
public int fadeOut { get; set; }
public int timeOut { get; set; }
public int extendedTimeOut { get; set; }
public bool debug { get; set; }
/// <summary>
///
/// </summary>
/// <param name="type"></param>
/// <param name="message"></param>
/// <param name="dtype"></param>
public Toast(MessageType type, string message, DisplayType dtype = DisplayType.TopRight)
{
this.type = type.ToString();
this.message = message;
this.DType = dtype;
this.fadeIn = 300;
this.fadeOut = 1000;
this.timeOut = 5000;
this.extendedTimeOut = 1000;
this.debug = false;
}
/// <summary>
///
/// </summary>
public DisplayType DType
{
set
{
this.positionClass = GetPositionClass(value);
}
}
/// <summary>
///
/// </summary>
/// <param name="dtype"></param>
/// <returns></returns>
private string GetPositionClass(DisplayType dtype)
{
string position = string.Empty;
switch (dtype)
{
case DisplayType.TopLeft:
position = ToastrProperties.TopLeft;
break;
case DisplayType.TopFull:
position = ToastrProperties.TopFull;
break;
case DisplayType.BottomRight:
position = ToastrProperties.BottomRight;
break;
case DisplayType.BottomLeft:
position = ToastrProperties.BottomLeft;
break;
case DisplayType.BottomFull:
position = ToastrProperties.BottomFull;
break;
case DisplayType.TopRight:
default:
position = ToastrProperties.TopRight;
break;
};
return position;
}
/// <summary>
///
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static List<Toast> DeserializeAll(string json)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<Toast>>(json);
}
/// <summary>
///
/// </summary>
/// <param name="allToast"></param>
/// <returns></returns>
public static string SerializeAll(List<Toast> allToast)
{
return Newtonsoft.Json.JsonConvert.SerializeObject(allToast);
}
}
This uses two special enumerations I created for the Toastr display locations, and message window types so that they could be dynamic.
public enum MessageType
{
success,
info,
warning,
error,
};
And
public enum DisplayType
{
TopRight,
TopLeft,
TopFull,
BottomRight,
BottomLeft,
BottomFull,
};
Once you've created the Toastr class you have to override the OnException method of your Controller. There is another way this has to happen if you are using an ApiController which I will also show.
Also you will need to create a ToastrProperties class, seen below.
public static class ToastrProperties // TODO: Add in the descriptions for each of these properties
{
/// <summary>
///
/// </summary>
public const string MessagesKey = "messages";
/// <summary>
///
/// </summary>
public const string BottomFull = "toast-bottom-full-width";
/// <summary>
///
/// </summary>
public const string BottomLeft = "toast-bottom-left";
/// <summary>
///
/// </summary>
public const string BottomRight = "toast-bottom-right";
/// <summary>
///
/// </summary>
public const string TopFull = "toast-top-full-width";
/// <summary>
///
/// </summary>
public const string TopLeft = "toast-top-left";
/// <summary>
///
/// </summary>
public const string TopRight = "toast-top-right";
/// <summary>
///
/// </summary>
}
Controller Example:
I suggest creating a special base class for your controllers so that they all inherit from it, and it can help with other things later in your application. Here is my base controller class.
/// <summary>
/// The Base Controller for the P3 Application. All Controllers that are not
/// API Controllers should derive from this
/// </summary>
public abstract class BaseController : Controller
{
// TODO: Preferably, new up through injection through constructor
protected Services.P3KendoDataAccess Data = PortalServices.DataAccess;
/// <summary>
/// Handles any and all unhandled exceptions that occur
/// within a standard MVC controller. This will Log the Error
/// using NLog, and then display an error to he user using Toastr
/// which will show that there was a problem within the controller
/// </summary>
/// <param name="filterContext"></param>
protected override void OnException(ExceptionContext filterContext)
{
try
{
// Log the original error, and mark it as fixed so that the message isn't displayed to the User
// TODO: Assign a GUID to the error, and display that to the user so that it can be referenced back to the exception
P3Log.Error(filterContext.Exception, System.Web.HttpContext.Current);
filterContext.ExceptionHandled = true;
((BaseController)filterContext.Controller).ShowMessage(new Toast(MessageType.error, filterContext.Exception.Message, DisplayType.TopRight), false);
}
catch (Exception excep)
{
P3Log.Error(new Exception(ToastrRes.BaseControllerException, excep));
}
return;
}
}
After you've added this to your project just set your controllers to derive from this class instead of Controller, and that will set this method up.
WebAPI Controller Example:
This one is a little more involved because you can't just inherit from the ApiController class like in the above example. You have to create an Exception Filter Attribute that you would apply to each ApiController. I will show you how you can do it without manually applying it since you will want it on every controller anyways most likely.
First you have to create the Filter Attribute:
public class P3ApiExceptionFilterAttribute : ExceptionFilterAttribute // TODO: Add information to the summaries
{
/// <summary>
///
/// </summary>
/// <param name="Context"></param>
public override void OnException(HttpActionExecutedContext Context)
{
try
{
List<Toast> Toasts = new List<Toast>();
// Create a response and add a header for the Message to be displayed using the ajaxError event
Context.Response = Context.Request.CreateResponse();
// Log the error that occurred here
P3Log.Error(Context.Exception);
// Go through all of the Headers that match our messages key. There should only ever be
// one, but since the Web API stuff handles this differently I want to cover our bases
foreach (var header in Context.Request.Headers.Where(x => x.Key.Equals(ToastrProperties.MessagesKey)))
{
// Check the header to see if it's null, and if it's not, and there are values for
// the header, add them to the Toasts list so that they will be re-added to the error
// response header, and actually be received by the client
if (header.Value != null)
{
foreach (string str in header.Value)
{
if (!string.IsNullOrEmpty(str))
{
try
{
Toasts.AddRange(Toast.DeserializeAll(str));
}
catch { } // Do nothing here
}
}
}
}
// Add the Exception Toast
Toasts.Add(new Toast(MessageType.error, GlobalRes.ApplicationError, DisplayType.TopRight));
// Add the header for the response so that the messages will be displayed
// once the response gets back to the client
if (Toasts != null && Toasts.Any())
{
string Messages = Toast.SerializeAll(Toasts);
if (!string.IsNullOrEmpty(Messages))
{
// Adding a single Response Header
Context.Response.Headers.Add(ToastrProperties.MessagesKey, Messages);
}
}
}
catch (Exception excep)
{
P3Log.Error(ToastrRes.ApiToastrException, excep);
}
base.OnException(Context);
}
}
Next you need to add your Filter Attribute to all of your Api Controllers. The easiest way to do this is to go into your "WebApiConfig.cs" file, and inside of the Register method just put:
// Add the exception handler for the API controllers
config.Filters.Add(new P3ApiExceptionFilterAttribute());
This will setup your WebApi Controllers.
NEXT Step
After you've added either/both methods you need to do a few other things.
First before we go into that though it's important to let you know that what we are doing here in these two methods are actually handling the errors, and logging them within our system. Then we are using the Toast objects static methods to serialize and deserialize JSON into the response/ temp headers of the request so that it's then passed back to the client as JSON and can be handled by the browser upon both async, or post back page requests. But we will get to that in a second.
Because I didn't want this to only be used for passing exception messages to the client I also setup extensions for both the BaseController, and ApiController methods so that they could call a "ShowMessage" method and send Toastr methods down to the client.
Here is the Base Controller version of the Extension:
public static class ControllerExtensions
{
/// <summary>
///
/// </summary>
/// <param name="controller"></param>
/// <param name="toast"></param>
/// <param name="showAfterRedirect"></param>
public static void ShowMessage(this Controller controller, Toast toast, bool showAfterRedirect = false)
{
try
{
if (toast != null)
{
List<Toast> allToast = new List<Toast>();
// Pull the existing messages from the Temp, or Response
// based on the redirect option, and assign it to a string variable
string messagesJson = showAfterRedirect ?
controller.TempData[ToastrProperties.MessagesKey].ToString()
: controller.Response.Headers[ToastrProperties.MessagesKey];
// Deserialize the JSON into the toast list
if (!string.IsNullOrEmpty(messagesJson))
{
try
{
allToast = Toast.DeserializeAll(messagesJson as string);
}
catch { } // Do nothing here
}
// Add a new Toast to the list
allToast.Add(toast);
// Serialize the List
string SerializedString = Toast.SerializeAll(allToast);
if (!string.IsNullOrEmpty(SerializedString))
{
if (showAfterRedirect)
{
controller.TempData[ToastrProperties.MessagesKey] = SerializedString;
}
else
{
controller.Response.Headers[ToastrProperties.MessagesKey] = SerializedString;
}
}
}
}
catch (Exception excep)
{
P3Log.Error(new Exception(ToastrRes.ShowMessageException, excep));
}
}
}
Here is the Web Api version of the same extension:
public static class ApiControllerExtensions
{
/// <summary>
/// Show a message to the user Using Toastr
/// </summary>
/// <param name="controller"></param>
/// <param name="messageType"></param>
/// <param name="message"></param>
public static void ShowMessage(this ApiController controller, Toast ToastMessage)
{
try
{
string message = string.Empty;
List<Toast> Messages = new List<Toast>();
var header = controller.Request.Headers.FirstOrDefault(x => x.Key.Equals(ToastrProperties.MessagesKey));
if (header.Value != null && header.Value.Any())
{
string hString = header.Value.FirstOrDefault();
if (!string.IsNullOrEmpty(hString))
{
try
{
Messages = Toast.DeserializeAll(hString);
}
catch {} // Do nothing here
}
}
// Add the message to the existing messages in the
// header
Messages.Add(ToastMessage);
message = Toast.SerializeAll(Messages);
if (!string.IsNullOrEmpty(message))
{
// Remove the old header, and put the new one in
controller.Request.Headers.Remove(ToastrProperties.MessagesKey);
controller.Request.Headers.Add(ToastrProperties.MessagesKey, message);
}
}
catch (Exception excep)
{
// Log here with NLog
P3Log.Error(new Exception(ToastrRes.ShowMessageException, excep));
}
}
}
Like any standard extension you need to make sure to have the namespace included otherwise it won't work.
Final Step:
Install the Toastr NUGET Package, or get it online, and make sure that it's added to your bundles, or the method you are using to add scripts to your Views.
Now you need to add the Javascript to the _Layout.cshtml in your application.
<script type="text/javascript">
// Setup message triggers and display all messages for this page
$(document).ready(function () {
var tempMessages = '#Html.Raw(TempData[ToastrProperties.MessagesKey])';
if (!tempMessages) {
tempMessages = '[]';
}
var viewMessages = '#Html.Raw(Response.Headers[ToastrProperties.MessagesKey])';
if (!viewMessages) {
viewMessages = '[]';
}
var allMessages = $.parseJSON(tempMessages).concat($.parseJSON(viewMessages));
handleAjaxMessages();
displayMessages(allMessages);
});
// Display all messages that are listed within the Header of the call.
// These messages are all stored in a serialized XML string that is then Decoded by the RenderMessages method
function displayMessages(messages) {
$.each(messages, function (idx, msg) {
toastr[msg.type](msg.message, msg.title, {
fadeIn: msg.fadeIn,
fadeOut: msg.fadeOut,
timeOut: msg.timeOut,
positionClass: msg.positionClass,
onclick: function() {
var wnd = $("#AppMessageWindow").data("kendoWindow");
wnd.content(msg.message).center().open();
}
});
});
}
// Add methods for events that are both ajaxSuccess, and ajaxError
function handleAjaxMessages() {
$(document).ajaxSuccess(function (event, request) {
checkAndHandleMessageFromHeader(request);
}).ajaxError(function (event, request) {
checkAndHandleMessageFromHeader(request);
});
}
// Get messages from the Response header of the request, and display them as
// a message using Toastr
function checkAndHandleMessageFromHeader(request) {
// pull the messages from the Response Header
var msgs = request.getResponseHeader('#ToastrProperties.MessagesKey');
if (!msgs) {
msgs = '[]'
}
var allMessages = $.parseJSON(msgs)
displayMessages(allMessages);
}
</script>
This requires some explanation. The first function in the script loads the initial response / temp headers because on the initial page load there isn't a standard request that is triggered within the page. Or at least I couldn't find one that would allow access to the headers. So these are placed in using Razor.
The rest should be pretty straight forward. It uses the JSON to pop a toastr message, and adds events to the Ajax requests so that any Toastr messages that come back to it are handled properly.
I'm pretty sure I've got everything in here. If you have any questions, or something is missing when you try to implement it, post on here or PM me and I'll update my post. I hope this helps others who are attempting to do the same thing. :)
Enjoy!

Categories