Knockout and breeze.js take method is not working Paging - javascript

Datacontext.js
var manager = new breeze.EntityManager('breeze/BreezeData');
function getMenuItems() {
var query = new breeze.EntityQuery("Products").take(5);
return manager.executeQuery(query);
}
Products.js
function loadProducts() {
return datacontext.getMenuItems().then(function (data) {
data.results.forEach(function (item) {
self.menuProducts.push(item);
});
}).fail(function (data) {
logger.logError('Failed to load Products', null, "", true);
});
}
Action Method
[HttpGet]
public IEnumerable<MenuItem> Products()
{
var venueId = GetCurrentVenue().ID;
return _contextProvider.Context.MenuItem.Where(mi => mi.Venue.ID == venueId);
}
It returns almost 45 records but i am using take(5) here and that take isn't working and returning the same result.I am a newbie so i have just started to implement it.
Thanks in advance..

Change action method to:
[HttpGet]
public IQueryable<MenuItem> Products()
{
var venueId = GetCurrentVenue().ID;
return _contextProvider.Context.MenuItem.Where(mi => mi.Venue.ID == venueId);
}
In case it still doesn't work, try adding orderBy in case server isn't sure what would actually be first 5 items.

Related

Autodesk Design Automation "Value cannot be null. (Parameter 'ForgeConfiguration.ClientId')"

I´ve downloaded the Forge Design Automation sample from the following link:
https://learnforge.autodesk.io/#/tutorials/modifymodels
But the downloable code example is not working fine. When any async method who involves the DesignAutomation API is called I get -> Value cannot be null. (Parameter 'ForgeConfiguration.ClientId'). So, I would like to know how it works and how I can set the ClientId in the ForgeConfiguration class or else if I making something else wrong. I attach a fragment of code where I get the error.
[HttpGet]
[Route("api/forge/designautomation/engines")]
public async Task<List<string>> GetAvailableEngines()
{
List<string> allEngines = new List<string>();
try
{
dynamic oauth = await OAuthController.GetInternalAsync();
// define Engines API
string paginationToken = null;
while (true)
{
Page<string> engines = await _designAutomation.GetEnginesAsync(paginationToken);
allEngines.AddRange(engines.Data);
if (engines.PaginationToken == null)
break;
paginationToken = engines.PaginationToken;
}
allEngines.Sort();
}
catch (Exception error) {
throw error;
}
return allEngines; // return list of engines
}
And the call of the method:
function prepareLists() {
list('engines', 'api/forge/designautomation/engines');
}
function list(control, endpoint) {
$('#' + control).find('option').remove().end();
jQuery.ajax({
url: endpoint,
success: function (list) {
if (list.length === 0)
$('#' + control).append($('<option>', { disabled: true, text: 'Nothing found' }));
else
list.forEach(function (item) { $('#' + control).append($('<option>', { value: item, text: item })); })
}
});
}
Did you forget to set the Forge App Keys in the Environment Variables of your project, check the page at https://learnforge.autodesk.io/#/environment/setup/netcore_da

jsTree Lazy Loading with C# & Web API

I am currently using jsTree v3.3.10 and attempting to load the structure via a Web API call.
JavaScript:
$('#ksbBrowser').jstree({
core: {
data: {
type: 'GET',
dataType: 'json',
contextType: 'application/json',
url: function (node) {
if (node.id == "#") {
return '/api/search/talent/ksbtree/root';
}
else {
return '';
}
},
data: function (node) {
return { id: node.id };
}
}
}
});
C# WebAPI EndPoint Code:
[HttpGet, Route("api/search/talent/ksbtree/{Type}")]
public String GetKSBTree(String Type)
{
List<DataModels.JSTreeNode> lNodes = new List<JSTreeNode>();
String sJSON = "";
switch (Type)
{
case "root":
var first = new[] {
new {
id = "root-id",
text = "KSBs",
state = new { opened = true },
children = true
}
};
sJSON = JSONHelper.Serialize(first);
break;
default:
break;
}
return sJSON;
}
I am getting json returned via the call and the appropriate contentType headers are there, but jsTree is not loading the tree correctly. This is the sample return of the JSON via postman:
"[{\"id\":\"root-id\",\"text\":\"KSBs\",\"state\":{\"opened\":true},\"children\":true}]"
But as you can see here, jsTree is not processing the JSON correctly.
Does anyone have any idea at all what I am doing wrong.
I figured this out. The WebAPI was returning type of string and jsTree does not do it's own parseJSON internally. To fix this I changed the return type of my end point to be an HTTPResponseMessage.
public HttpResponseMessage GetKSBTree(String Type)
Then I format the response message and return it:
HttpResponseMessage rmMessage = new HttpResponseMessage() { Content = new StringContent(sJSON) };
rmMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
return rmMessage;

Load AJAX collections in order in JavaScript

How to ensure, in JavaScript (jquery) that some actions are performed one after other, in an order.
Say, I need to load schools collection BEFORE loading teachers, in order to assing the myTeacher.SchoolName = schools[myTeacher.SchoolId].name;
The pseudo code bellow:
const studentsUrl='api/students', teachersUrl='api/teachers', schoolsUrl='api/schools';
let students = null, teachers = null, schools = null;
$(document).ready(function () {
getSchools();
getTeachers();
getStudents();
});
function getSchools() {
$.get(schoolsUrl, function (data) {
window.schools = data;
});
}
function getTeachers() {
$.get(teachersUrl, function (data) {
window.teachers = data;
// >>> SHOULD BE SURE, SCHOOLS already loaded!!!
$.each(teachers, function (key, item) {
item.school = schools[item.schoolId].name;
});
});
}
function getStudents() {
$.get(studentsUrl, function (data) {
window.students = data;
// >>> SHOULD BE SURE, TEACEHRS already loaded!!!
$.each(students, function (key, item) {
item.teacher = teachers[item.teacherId].name;
});
});
}
PS.
Is there another way to assure order but the encapsulation of one function at the end of another?
As others already suggested you can chain requests.
I made few changes to your code.
Added Strict Mode it helps to prevent bugs
The code wrapped in IFFE in order to prevent global pollution
If all apis belong to the same server you can process all this data on server side
and return one filled json.
in this way your server will do a little extra work on constructing this json but in other hand you will make only one ajax request instead of 3.
This will work faster and you can cache this json for some time
Code for the first solution
(function () {
'use strict';
const studentsUrl = 'api/students';
const teachersUrl = 'api/teachers';
const schoolsUrl = 'api/schools';
let students = null;
let teachers = null;
let schools = null;
var scoolData = {
schools: null,
teachers: null,
students: null
};
$(document).ready(function () {
getSchools().then(function (schools) {
scoolData.schools = schools;
getTeachers().then(function (teachers) {
scoolData.teachers = teachers;
$.each(scoolData.teachers, function (key, item) {
item.school = scoolData.schools[item.schoolId].name;
});
});
});
});
function getSchools() {
return $.get(schoolsUrl);
}
function getTeachers() {
return $.get(teachersUrl,
function (result) {
scoolData.teachers = result;
// >>> SHOULD BE SURE, SCHOOLS already loaded!!!
$.each(teachers, function (key, item) {
item.school = scoolData.schools[item.schoolId].name;
});
});
}
})();
Since you only need all the results available and each request does not depend on the previous you can use jQuery.when
let students = null;
let teachers = null;
let schools = null;
$(document).ready(function() {
$.when(
getSchools(),
getTeachers()
).done(function(shoolResults, teacherResults) {
window.schools = shoolResults;
window.teachers = teacherResults;
handleTeachers();
getStudents();
});
function getSchools() {
return $.ajax({
type: 'GET',
url: schoolsUrl
});
}
function getTeachers() {
return $.ajax({
type: 'GET',
url: teachersUrl
});
}
function handleTeachers() {
$.each(teachers, function (key, item) {
item.school = schools[item.schoolId].name;
});
}
});
If you want them in order (though I'm not sure I understand why, since you retrieve all schools/teachers/students anyway), you can simply do this.
Note: get* functions are dummies in the following sample. Instead, just return the result of $.get calls from them:
function getSchools() {
return Promise.resolve({1: {name: 'school1'}});
}
function getTeachers() {
return Promise.resolve({1: {name: 'teacher1', schoolId: 1}});
}
function getStudents() {
return Promise.resolve({1: {name: 'student1', teacherId: 1}});
}
(async () => {
const schools = await getSchools();
const teachers = await getTeachers();
const students = await getStudents();
// Alternative for the $.each code
Object.values(teachers).forEach(teacher => teacher.school = schools[teacher.schoolId].name);
Object.values(students).forEach(student => student.teacher = teachers[student.teacherId].name);
console.log(schools, teachers, students);
})();
Another note: this is ES8 code, I'll post a non async/await version if you need to support older browsers and can't use a transpiler like Babel.
Non ES8-dependent code:
function getSchools() {
return Promise.resolve({1: {name: 'school1'}});
}
function getTeachers() {
return Promise.resolve({1: {name: 'teacher1', schoolId: 1}});
}
function getStudents() {
return Promise.resolve({1: {name: 'student1', teacherId: 1}});
}
let schools = null, teachers = null, students = null;
getSchools().then(_schools => {
schools = _schools;
return getTeachers();
}).then(_teachers => {
teachers = _teachers;
return getStudents();
}).then(_students => {
students = _students;
for (var _ in teachers) {
teachers[_].school = schools[teachers[_].schoolId].name;
}
for (var _ in students) {
students[_].teacher = teachers[students[_].teacherId].name
}
console.log(schools, teachers, students);
});
Call getTeachers(); when getSchools(); return success or complete, success preferred since complete runs if there's an error..
I think you are looking for this one.
getSchools().done(function(data){
var someId = data.findThatId;
getTeachers(someId);
});
You will need to return data from ajax call to get data in done.
You may load them asynchronously but you have to wait until both calls are finished.
To achieve this, add return before your ajax calls and combine the results in your ready function (not in the success handler of the teachers call):
let schoolsPromise = getSchools();
let teachersPromise = getTeachers();
$.when(schoolsPromise, teachersPromise)
.then((schools, teachers) => {
$.each(teachers, (key, item) => {
item.school = schools[item.schoolId].name;
});
});

How to pass array as parameter to $http.get in Angularjs

Problem Statement
I have a javascript array which i want to pass as a parmeter to $http.get in AngularJs. This array will be passed to action method in MVC. what should be the syntax? Please Help me. I am stuck here.
The array being passed is javascript array
Angular Directive
$scope.selectedIdArray = [];
$scope.selectedIdArray.push({ id: $scope.selectedId })
$scope.$parent.getProjects($scope.selectedIdArray);
Angular Controller
$scope.getProjects = function (selectedIdArray) {
$http.get('Home/GetAllProjects', { params: { "parentId[]": selectedIdArray } })
.then(function (data) {
$scope.projects = [];
angular.forEach(data.data, function (value, index) {
$scope.projects.push({ id: value.N_LevelID, label: value.T_LevelName }
);
});
})
.catch(function (data) {
console.error('Gists error', data.status, data.data);
})
}
MVC Controller Action Method
public JsonResult GetAllProjects(int?[] parentId = null)
{
iMetricsEntities dbcontext = new iMetricsEntities();
JsonResult jr = new JsonResult();
if (parentId == null)
{
jr.Data = dbcontext.Levels.Where(objelevel => objelevel.N_LevelTypeID == 2 && objelevel.B_Active);
jr.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
//return new JsonResult
//{
// Data = dbcontext.Levels.Where(objelevel => objelevel.N_LevelTypeID == 2 && objelevel.B_Active),
// JsonRequestBehavior = JsonRequestBehavior.AllowGet
//};
}
else if (parentId != null)
{
foreach (var id in parentId)
{
jr.Data = dbcontext.Levels.Where(objelevel => objelevel.N_LevelTypeID == 2 && objelevel.B_Active && objelevel.N_ParentID == id);
jr.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
}
return jr;
}
If you define your controller action like this:
public JsonResult GetAllProjects(int[] parentId)
{
// Stuff goes here
}
You can call it like this:
$http.get('Home/GetAllProjects', { params: { "parentId": [1, 2, 3, 42] } })
.then(function(response) {
// stuff goes here
});
The reason this works is because query strings can be specified multiple times. Both $http and MVC interpret these as arrays.
In the above example, this is the URL that gets generated by $http, which the controller action model binds to an array:
http://localhost:56976/Home/GetAllProjects?parentId=1&parentId=2&parentId=3&parentId=42
$http(
method: 'GET',
url: ''Home/GetAllProjects'',
params: {
parentId: JSON.stringify(selectedIdArray )
}
)

Web API string parameters and POST values

I am using a jQuery plugin, jTable. The plugin has the following function to load the table:
$('#PersonTable').jtable('load', { CityId: 2, Name: 'Halil' });
The values in the load function is send as POST data. The plugin also sends two query string parameters (jtStartIndex, jtPageSize) through the URL for paging the table.
An example in the documentation shows a function on how to handle this in ASP.NET MVC but not in Web API Example :
[HttpPost]
public JsonResult StudentListByFiter(string name = "", int cityId = 0, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = null)
{
try
{
//Get data from database
var studentCount = _repository.StudentRepository.GetStudentCountByFilter(name, cityId);
var students = _repository.StudentRepository.GetStudentsByFilter(name, cityId, jtStartIndex, jtPageSize, jtSorting);
//Return result to jTable
return Json(new { Result = "OK", Records = students, TotalRecordCount = studentCount });
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
How my function currently looks: It works fine except that I can't manage to read the POST data (name param):
public dynamic ProductsList(string name = "", int jtStartIndex = 0, int jtPageSize = 0 )
{
try
{
int count = db.Products.Count();
var products = from a in db.Products where a.ProductName.Contains(name) select a;
List<Product> prods = products.OrderBy(x => x.ProductID).ToList();
return (new { Result = "OK", Records = prods, TotalRecordCount = count });
}
catch (Exception ex)
{
return (new { Result = "ERROR", Message = ex.Message });
}
}
My jTable load: (This get called when the user enters text in a input)
$('#ProductTable').jtable('load', {
name: $('#prodFilter').val()
});
I would appreciate any help with how to read both the string parameters in the URL and the POST data in a Web API function.
EDIT:
I used an alternative way to send the data to the API. Instead of sending it in the load function formatted as JSON I used a function for the listAction and sent the data through the URL (See jTable API reference for details):
listAction: function (postData, jtParams) {
return $.Deferred(function ($dfd) {
$.ajax({
url: 'http://localhost:53756/api/Product/ProductsList?jtStartIndex=' + jtParams.jtStartIndex + '&jtPageSize=' + jtParams.jtPageSize + '&name=' + $('#prodFilter').val(),
type: 'POST',
dataType: 'json',
data: postData,
success: function (data) {
$dfd.resolve(data);
},
error: function () {
$dfd.reject();
}
});
});
}
To reload the table based on your filtered results:
$('#ProductTable').jtable('load');
Instead of this:
$('#ProductTable').jtable('load', {
name: $('#prodFilter').val()
});
Try applying the [FromBody] attribute to the name parameter
public dynamic GetProductList([FromBody]string name = "", int jtStartIndex = 0, jtPageSize = 0)
{
...
}
The default binder in Web API will look in the URI for simple types like string, specifying the FromBody attribute will force it to look in the body.

Categories