Based on this article i’ve created an Excel TaskPane App
The controller
using DatabaseWeb.Models;
using System.Web.Mvc;
namespace DatabaseWeb.Home
{
public class HomeController : Controller
{
// GET: Home
public ActionResult GetEmployee()
{
Employee john = new Employee
{
Id = 1,
FirstName = "John",
LastName = "Smith"
};
return Json(new { employee = john }, JsonRequestBehavior.AllowGet);
}
}
}
The model
namespace DatabaseWeb.Models
{
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
JAVASCRIPT
$(document).ready(function () {
$('p#getEmployee').click(function () {
GetEmployeeUsingAjax();
});
});
function GetEmployeeUsingAjax() {
$.ajax({
type: 'GET',
url: 'Home/GetEmployee',
success: function (emp) {
$('#id').text(emp.employee.Id);
$('#firstName').text(emp.employee.FirstName);
$('#lastName').text(emp.employee.LastName);
},
error: function (emp) {
//alert('error');
return "error";
}
});
}
body home.html
<div id="id"></div>
<div id="firstName"></div>
<div id="lastName"></div>
<p id="getEmployee">Get Employee</p>
When I run the project it generate the id, firstname and lastname in my task pane. GREAT! So my next question is very simple. How can I generate the lastname in Excel (home.js)
function loadSampleData() {
var values = GetEmployeeUsingAjax(lastname);
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
sheet.getRange("A1").values = values;
return ctx.sync();
})
.catch(errorHandler);
}
The above code won't work.
What is the exact syntax? The follow code show my intensions but does not work.
var values = GetEmployeeUsingAjax(lastname);
You may have a few problems with your code. The first one is that your function GetEmployeeUsingAjax does not return anything, ever. The real action is the asynch call to the success function. So you must either do your work of setting the excel values inside that function or pass another function through so it can be called from inside the success function.
Try that and if you still have problems, update the question.
Related
I have tried different methods that have been posted on this site, but nothing seems to work.
I want to create a clothing site (a personal project). The products on the site have their own class, that is built like this:
public class Product
{
public string ProductName { get; set; }
public string ProductPrice { get; set; }
public int Quantity { get; set; }
}
The shopping cart is another class that will contain a list of Product objects and this one is built like this:
public class ShoppingCart
{
[Key]
public int Id { get; set; }
List<Product> ProductList { get; set; }
public string ClientName { get; set; }
public string ClientAddress { get; set; }
public string ClientMail { get; set; }
}
I created an API Controller class and thought that would solve the problem. It looks like this:
[Route("api/Shopping")]
[ApiController]
public class ShoppingCartController : ControllerBase
{
[HttpPost]
public ShoppingCart Save([FromBody] ShoppingCart s)
{
return s;
}
}
In my JavaScript code I create my JSON object and try to post it like this:
var orderB = document.getElementById("orderB");
orderB.addEventListener("click", function () {
var inputName = document.getElementById("inputName").value;
var inputAddress = document.getElementById("inputAddress").value;
var inputMail = document.getElementById("inputMail").value;
var auxArray = [];
for (var i = 0; i < productsAux.length; i++) {
auxArray[i] = { "productName": productsAux[i].titlu, "productPrice": productsAux[i].pret, "quantity": localStorage.getItem(productsAux[i].titlu)};
}
var shoppingCart = {
productList: auxArray,
clientName: inputName,
clientAddress: inputAddress,
clientMail: inputMail
};
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "api/shopping/save",
contentType: "application/json charset=utf-8",
}).done(function (res) {
alert(res);
});
After I push the order button on my page I expect to see the alert pop-up with the callback result which I suppose is the ShoppingCart object that is created using the JSON that I send.
For those coming on later, I would suggest checking that your types are correct on both ends. For instance, if your JS is posting a byte array and C# tries to convert it to an int, the whole object (not just that prop) will be null.
This has caught me many a time.
I opened the Network tab and I got this: I got a 404 (kind of
expected that) , the name of the method 'save' , a type of 'xhr' and a
size of 45B.
The 404 error obviously means the url/routing is wrong. Here to solve it ,you have two ways to achieve.
First way:
You can change url to "api/shopping" in ajax as follow:
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "api/shopping",
contentType: "application/json charset=utf-8",
}).done(function (res) {
alert(res);
})
Second way:
You can change the path name
of Save action by Attribute routing with Http verb attributes as follow:
[Route("api/Shopping")]
[ApiController]
public class ShoppingCartController : ControllerBase
{
[HttpPost("Save")]
public ShoppingCart Save([FromBody] ShoppingCart s)
{
return s;
}
}
Update
According to your comment, in addition to the above updates, you also need to modify the routing settings as follows:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Debug result:
The basic problem is this. I'm using CKEditor for an interface for a blog post of sorts. CKEditor gets the wordcount, but I have to use some client-side JavaScript to clean it up. I want to pass the wordcount into the database so I know how many words each post has.
I have a viewmodel for the post:
public class NewStoryViewModel
{
[Required]
public string Title { get; set; }
[Required]
public string Content { get; set; }
[Required]
public int Genre { get; set; }
public IEnumerable<Genre> Genres { get; set; }
[Required]
public int StoryType { get; set; }
public IEnumerable<StoryType> StoryTypes { get; set; }
public int WordCount { get; set; }
[Required]
public int StoryAgeRange { get; set; }
public IEnumerable<StoryAgeRange> StoryAgeRanges { get; set; }
[Required]
public int Visibility { get; set; }
public IEnumerable<Visibility> Visibilities { get; set; }
}
And the controller for the post:
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult New (NewStoryViewModel viewModel)
{
//confirm form data is valid
if (ModelState.IsValid)
{
//create new story object
var newStory = new Story
{
AuthorId = User.Identity.GetUserId(),
Title = viewModel.Title,
Content = viewModel.Content,
GenreId = viewModel.Genre,
StoryTypeId = viewModel.StoryType,
StoryAgeRangeId = viewModel.StoryAgeRange,
VisibilityId = viewModel.Visibility,
CreatedAt = DateTime.Now,
WordCount = viewModel.WordCount
};
//add new story to db
dbContext.Stories.Add(newStory);
//save db
dbContext.SaveChanges();
return RedirectToAction("Index", "Story");
}
else
{
return View(viewModel);
}
}
On the client-side in the razor view, I have this:
$(document).ready(function () {
$('#addStoryBtn').on('click', function () {
//get the content of the div
var wordcount = $('#cke_wordcount_Content').html();
//chop off the words before the number in the string
var slicedWordCount = wordcount.slice(6);
//remove any excess white space
var trimmedWordCount = slicedWordCount.trim();
//capture the index of the slash
var indexOfSlash = trimmedWordCount.indexOf("/");
//split the string at the slash to get the words used out of the total allotted
var finalWordCount = trimmedWordCount.slice(0, indexOfSlash);
//$.ajax({
// url: "/story/new",
// type: 'POST',
// data: {
// WordCount = finalWordCount
// },
// success: function (data) {
// console.log("Success")
// },
// error: function (error) {
// console.log("error is " + error);
// }
//})
});
});
I do this because CKEditor prints the word count out of the maximum like this:
Words: 4/5000
so I use a bit of JS to remove everything I don't need and keep the number before the slash.
But the ajax post didn't work (stepping through the controller, it returns 0).
I thought about using a hiddenfield in the view. Something like:
#Html.Hidden(new { WordCount = finalWordCount })
But the razor view gives me an error that finalWordCount doesn't mean anything in the current context. I surmise it's because finalWordCount is subject to the button click and since the addPost button hasn't been clicked, finalWordCount is undefined.
Any suggestions on how to pass the wordcount to the viewmodel?
You've mentioned in the comments that you're experiencing a 500 internal server error, which I'm guessing is after you've tried Shyju's suggestion to fix the invalid JSON. My guess is you're unable to even debug the controller action right now because it's expecting an anti-forgery token to be passed to it, but you're not sending that in the body of the POST request.
To fix that, try this:
var form = // selector for your form
var token = $('input[name="__RequestVerificationToken"]', form).val();
$.ajax({
url: "/story/new",
type: 'POST',
data: {
__RequestVerificationToken: token,
WordCount: finalWordCount
},
success: function (data) {
console.log("Success")
},
error: function (error) {
console.log("error is " + error);
}
});
That should hopefully fix the validation error, allowing you to at least reach the action.
The MVC application is probably expecting a json format request body, as
that is the default configuration of asp.net MVC.
So before posting the data to the server you need to stringify the model to a proper json.
Try it like this
var data = JSON.stringify({WordCount: finalWordCount});
$.ajax({
url: "/story/new",
type: 'POST',
data: data,
success: function (data) {
console.log("Success")
},
error: function (error) {
console.log("error is " + error);
}
})
I am using https://github.com/ichord/At.js library to achieve autocomplete.
But it shows a list of "undefined" dropdown when I am using remoteFilter like they said in https://github.com/ichord/At.js/wiki/How-to-use-remoteFilter .
Model:
public class CaseHistory
{
public int CaseHistoryId { get; set; }
[Display(Name = "Symptom/Disease")]
[Required(ErrorMessage = "Please enter symptom or disease")]
public string SymptomOrDisease { get; set; }
public string Description { get; set; }
}
API action code:
private ApplicationDbContext db = new ApplicationDbContext();
// GET api/CaseHistories
public IQueryable<CaseHistory> GetCaseHistories()
{
return db.CaseHistories;
}
Here is my code in the razor view:
var myUrl = 'https://localhost:44301/api/CaseHistories';
$('#inputor').atwho({
at: ":",
callbacks: {
/*
It function is given, At.js will invoke it if local filter can not find any data
query [String] matched query
callback [Function] callback to render page.
*/
remoteFilter: function(query, callback) {
$.getJSON(myUrl, { q: query }, function (data) {
callback(data);
});
}
}
});
Change the code in the controller to be:
public dynamic GetCaseHistories()
{
return db.CaseHistories.Select(x => x.SymptomOrDisease).ToList();
}
The issue is that the parameter you pass to callback should be array of strings.
If you really wanted to do this in js:
var myUrl = 'https://localhost:44301/api/CaseHistories';
$('#inputor').atwho({
at: ":",
callbacks: {
/*
It function is given, At.js will invoke it if local filter can not find any data
query [String] matched query
callback [Function] callback to render page.
*/
remoteFilter: function(query, callback) {
$.getJSON(myUrl, { q: query }, function (data) {
var targetData = [];
for(var i = 0;i < data.length;i++){
targetData.push(data[i].SymptomOrDisease);
}
callback(targetData);
});
}
}
});
I have a form that has two sections. 3 input fields and another section with 10 checkboxes.
public class Customerproductdto
{
public string CustomerNumber { get; set; }
public string CustomerName { get; set; }
public string CustomerPhone { get; set; }
List<ProductDetails> GetAllChecked {get;set;}
}
public class ProductDetails
{
public string ProductName{ get; set; }
}
Here is jquery code I am using to get all the values of the checkboxes that were
checked on my form. They are about 10 and users could check everything.
var yourArray[]
$("input:checkbox[name=type]:checked").each(function(){
yourArray.push($(this).val());
});
Here is javascript that I use to collect the data and pass to my controller.
How can I pass in my array here all in one shot?
var objdata =
({
CustomerNumber: txtcustnumber,
CustomerName: txtcustname,
CustomerPhone: txtphone
//How do I pass the yourArray here?
});
var url = "#Url.Action("WriteToDb", "Home")";
var completeData = JSON.stringify({ 'Information': objdata });
$.get(url, { 'objdata': completeData }, function (data) {
$('#mainListContent').html(data);
});
Please note that I will like to deserialize this once I get to the controller.
Here is the method.
public ActionResult WriteToDb(string objdata)
{
Customerproductdto getAllTaskSaved = null;
try
{
var stripOffObjectName = JObject.Parse(objdata)["Information"];
var cleanedData = JsonConvert.DeserializeObject<Customerproductdto>(stripOffObjectName.ToString());
getAllTaskSaved = _dtcDataService.WriteTaskToDb(cleanedData, "Add");
}
catch (Exception ex)
{
logger.Error(ex);
}
return PartialView("_Taskdisplay", getAllTaskSaved);
}
I'm trying to figure out how to post an object from my form to a web api service. Within my controller I defined a model that I wanted to add input values to.
$scope.Label;
within my input fields I have them bound using ng-model such as:
<input type="checkbox" ng-model="label.isPublic" />
<input type="text" ng-model="label.labelName" required focus-me />
On the submission of the form these two fields a passed to my service and submitted to my WebApi
I have tried this submission in two ways:
function addLabel(label) {
var mylabel = encodeURIComponent(angular.toJson(label));
return $http.post('reportLibrary/createlabel/', { params: label }, {
}).then(function (response) {
return response.data;
});
};
and also as the following without declaring parameters
function addLabel(label) {
var mylabel = encodeURIComponent(angular.toJson(label));
return $http.post('reportLibrary/createlabel/', label , {
}).then(function (response) {
return response.data;
});
};
In the webAPI I have a method setup for the post
[Route ("reportLibrary/createlabel/")]
[HttpPost]
public DTOs.ReportLabel CreateLabel(DTOs.ReportLabel json)
{
DTOs.ReportLabel result = new DTOs.ReportLabel();
//.... do stuff
return result;
}
The ReportLabel (dto) is defined as follows:
public class ReportLabel
{
public Int64 LabelId { get; set; }
public string LabelName { get; set; }
public bool IsPublic { get; set; }
public IEnumerable<Report> Reports { get; set; }//placeholder?
}
The issue I have is when I post an object from my angular service it shows up as null within the API. If I change the type in the method to something like a JToken or JObject the values appear.
Can anyone help me understand why when I define the type that it is not passed across from angular?
thanks
It seems like you may be doing an extra step. You don't need to encode in json then pass in in json
return $http.post('reportLibrary/createlabel/', { LabelId: 101, LabelName: 'myname' }, {
then
public DTOs.ReportLabel CreateLabel([FromBody]ReportLabel reportLabel)
Take a look at the network values going by and you should see in debug tools or fiddler the actual posted values (form values).