I have the following BreezeController
[BreezeController]
public class BreezeController : ApiController
{
readonly EFContextProvider<MyContext> _ContextProvider = new EFContextProvider<MyContext>();
[HttpGet]
public string Metadata()
{
return _ContextProvider.Metadata();
}
....other controllers exposing model types....
[HttpGet]
public IQueryable<Size> Sizes()
{
return _ContextProvider.Context.Sizes;
}
}
which I access from the client from my DataContext.js with this
var getSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('Sizes').where('ID', '==', modelId)
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
All of this works just fine. I would like to add another route to my controller that has some specialized filtering done on the server.
[HttpGet]
public IQueryable<Size> GetUniqueSizes()
{
return //custom filtering logic here.
}
with the following javascript in my DataContext.js
var getUniqueSizes = function (sizesObservable, modelId) {
var query = entityQuery.from('GetUniqueSizes').where('modelID', '==', modelId).where('Approved', '==', 'True')
.orderBy('sortOrder').orderBy('size').orderBy('enteredDate');
return manager.executeQuery(query)
.then(querySucceeded);
function querySucceeded(data) {
if (sizesObservable) {
var intialValues = { size: ' Select a Size', sizeID: breeze.core.getUuid(), modelID: modelId };
createNullo(entityNames.size, 'Size', intialValues);
sizesObservable(data.results);
}
log('Retrieved [Sizes] from remote data source', data, false);
}
};
but when I do this I get the following error on the client
TypeError: Cannot read property 'toODataFragment' …localhost:63144/scripts/breeze.debug.js:12728:23)
Why is this route not working?
try changing the multiple orderBy statements to a multiple property sort.
.orderBy('sortOrder,size,enteredDate')
likewise, you might have better luck if you combine the where clauses.
Related
I am trying to pass some values as array on jobExport() collection and am getting an error Call to a member function jobsExport() on array. I understand that the collection need to populatet with modal collection value, but am trying to export multiple record(only record i select) from table , and to make this happend i thing i need to pass value as array from control to modal method, i have searched a loot to find a solution for this but i dont find anythin yet. Here is what i have done
Route
Route::any('export/jobs/{jobs}', [JobController::class, 'export']);
Pass data from vue to laravel
watch: {
selected: function(){
this.url = '/export/jobs/' + this.selected;
}
},
// After sending request on backend route will look like this
http://127.0.0.1:8000/export/jobs/1,2,4
Laravel controller
public function export($jobs)
{
return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
}
Model Method
public function jobsExport()
{
return Job::with('templates', 'teams')
->whereHas('templates', function ($q) {
$q->where('id', $this->id);
})
->get();
}
JobExport
class JobsExport implements WithStyles, FromCollection, WithMapping, WithHeadings
{
use Exportable;
private $jobs;
public function __construct($jobs)
{
$this->jobs = $jobs;
}
public function collection()
{
return $this->jobs->jobsExport();
}
public function map($jobsExport): array
{
// dd($jobsExport->templates->first()->template_name);
return [
$jobsExport->id,
$jobsExport->templates->implode('template_name', ', '),
$jobsExport->job_completed,
];
}
/**
* #return \Illuminate\Support\Collection
*/
public function headings():array
{
return[
'Id',
'Template',
'Completed',
];
}
}
Is the $jobs an id? If so, make it $jobId
public function export($jobId)
{
// assuming you have Job model which holds the jobs table
$jobs = Job::where('id', $jobId)->get();
return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
}
and in your export class
class JobsExport implements WithStyles, FromCollection, WithMapping, WithHeadings
{
use Exportable;
private $jobs;
public function __construct($jobs)
{
$this->jobs = $jobs;
}
public function collection()
{
// change this
//return $this->jobs->jobsExport();
// to
return $this->jobs;
}
public function map($jobsExport): array
{
// dd($jobsExport->templates->first()->template_name);
return [
$jobsExport->id,
$jobsExport->templates->implode('template_name', ', '),
$jobsExport->job_completed,
];
}
/**
* #return \Illuminate\Support\Collection
*/
public function headings():array
{
return[
'Id',
'Template',
'Completed',
];
}
}
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 controller where I send role parameter as true or false to js
Controller (relevant code):
public ActionResult GetForEdit()
{
var userRole = User.IsInRole("SuperAdmin");
#ViewBag.Role = userRole;
return Content(result, "application/json");
}
There I get true or false into #Viewbag
Ajax to call controller:
function GetModulLogWasteForEdit() {
debugger;
currentId = 0;
var manifest = $('#manifest').val();
$('#save').removeClass('hidden');
try {
$(function () {
$.ajax({
cache: false,
type: "get",
dataType: "json",
url: "/Log/GetForEdit", // controller
data: { manifest: manifest },
contentType: "application/json; charset=utf-8",
success: onGetModulLogWasteSuccess,
error: function (response) {
ErrorMessage("Error", GetTextError(response));
}
});
});
} catch (e) {
ErrorMessage("Error", e.message);
}
}
and now I populate kendo Grid to show fields, and there is where I want to use my viewbag so:
function onGetModulLogWasteSuccess(response) {
var role = '#ViewBag.Role'; // there I get my role bool
$("#lstInfo").kendoGrid({....
{
field: "", title: "Actions", width: "120px", hidden: role,
template: function (item) {
var id = item.Id;
var dropbox = "<div><div class='btn btn-danger'><a class='light' href='javascript:RemoveLogWaste(" + id + ");' role='button'><i class='fa fa-pencil-square-o'></i> Delete</a></div></div>";
return dropbox;
}
As you can see I use hidden:role parameter, but it always come true, when controller get it to false it hidden field too, Help is very appreciated. Regards
Update:
As Stephen answer, I change my controller to:
public ActionResult GetForEdit(string manifest)
{
string result = string.Empty;
var userRole = User.IsInRole("SuperAdmin");
try
{
result = new JavaScriptSerializer().Serialize(LogWasteModule.GetForEdit(manifest));
}
catch (Exception)
{
throw;
}
return Json(new
{
result,
role = userRole,
JsonRequestBehavior.AllowGet
});
}
GetForedith class:
public static List<LogEdit_Result> GetForEdit(string manifest)
{
var result = new List<LogEdit_Result>();
using (var context = new EF.A())
{
result = context.LogEdit(manifest).ToList();
}
return result;
}
But I get
his request has been blocked because sensitive information could be
disclosed to third party
You can't access the ViewBag from client-side javascript.
It is only available server-side(i.e. in your View/cshtml).
In order to do what you are trying to do, you will need to put the userRole value into the "result" that you are returning and then you will have it client-side, i.e.
public ActionResult GetForEdit()
{
var userRole = User.IsInRole("SuperAdmin");
// ...fill result (not shown)
return Json(new {
result = result,
role = userRole
}, JsonRequestBehavior.AllowGet);
}
And then
function onGetModulLogWasteSuccess(response) {
var role = response.role;
// response.result contains the "result" var from the server action.
$("#lstInfo").kendoGrid({....
}
The reason your role var is always true is because the string '#ViewBag.Role' is really the string '#ViewBag.Role' NOT the contents of the ViewBag(which again is not available client-side), and this string is truthy(evaluates as true when you ask it to be a boolean).
After Question Updated
Change your action to
public ActionResult GetForEdit(string manifest)
{
string result = string.Empty;
var userRole = User.IsInRole("SuperAdmin");
try
{
result = LogWasteModule.GetForEdit(manifest);
}
catch (Exception)
{
throw;
}
return Json(new
{
result = result,
role = userRole,
}, JsonRequestBehavior.AllowGet);
}
because
you shouldn't need to manually serialize your result as Json() will do it
the syntax of your Json(new...) is wrong: you need to use "field = value" syntax, NOT just "value" and the AllowGet needs to be a parameter to Json() NOT a value you add to the object.
I am attempting to follow 'angular best practice' by using an angular service that wraps my WebApi calls. I have it working for the most part but cannot figure out how to create the query string using the kendo datasourcerequest parameters in a way that parses out correctly on the webapi side.
Page
<div ng-controller="HomeCtrl as ctrl">
<div kendo-grid
k-pageable='{ "refresh": true, "pageSizes": true }'
k-ng-delay="ctrl.businessGridOption"
k-options="ctrl.businessGridOption"></div>
</div>
TS/JS
module Tql.Controllers {
'use strict';
export class BusinessWebApi {
public static $inject = ["$resource","$http"];
public static IID = "BusinessWebApi";
private httpService: ng.IHttpService;
public constructor($resource,$http) {
var vm = this;
vm.httpService = $http;
}
public GetBusinessCount() {
return this.httpService.get("/api/Business/GetBusinessCount");
}
public GetBusinesses(kendoOptions) {
console.log(JSON.stringify( kendoOptions));
return this.httpService.get("/api/Business/GetBusinesses"
+ "?page=" + kendoOptions.page
+ "&pageSize=" + kendoOptions.pageSize
+ "&sort[0][field]=" + kendoOptions.sort.split('-')[0] + "&sort[0][dir]=" + kendoOptions.sort.split('-')[1] );
//%5B = '['
//%5D = ']'
}
}
export interface IHomeCtrl {
Title: string
}
export class HomeCtrl implements IHomeCtrl {
public static $inject = [BusinessWebApi.IID];
public Title: string;
public businessGridOption: any;
public constructor(myservice: BusinessWebApi) {
var vm = this;
vm.Title = "Welcome to TQL Admin.";
vm.businessGridOption = {
sortable: true,
filterable: true,
pageable: true,
columns: [
{ field: "BusinessId", title: "ID" },
{ field: "BusinessLegalName", title:"Name"},
{ field: "CreatedDate", title: "Created" },
],
dataSource: new kendo.data.DataSource({
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize: 5,
transport: {
read: function (kendoOptions) {
this.options = { prefix: "" };
var data = kendo.data.transports["aspnetmvc-ajax"].prototype.options.parameterMap.call(this, kendoOptions.data, "read", false);
myservice.GetBusinesses(data)
.success(function (data) {
kendoOptions.success(data);
}).error(function (error) {
kendoOptions.error(error);
});
},
/* this only needs defined if you delegate the $get to the grid itself, which is bad practice for angular
since we have a service we need to call this manually (see above)
kendo.data.transports["aspnetmvc-ajax"].prototype.options.parameterMap.call
parameterMap: function (data, operation) {
return JSON.stringify(data);
}
*/
},
schema: { //this is needed to tell the grid how to parse the result object
data: function (data) { return data.Data; },
total: function (data) { return data.Total; },
errors: function (data) { return data.Errors; }
}
}),
};
}
}
angular.module('tql').service(BusinessWebApi.IID, BusinessWebApi); angular.module('tql').controller("HomeCtrl",HomeCtrl); }
WebApi
[RoutePrefix( "api/Business" )]
public class BusinessApiController : ApiController
{
private TQLContext db = new TQLContext();
[HttpGet]
[Route( "GetBusinesses" )]
public DataSourceResult GetBusinesses([FromUri]DataSourceRequest request)
{
//if (sort == null)
// sort = "BusinessId-asc";
//var req = this.Request;
return db.Businesses.Select(x => x).ToDataSourceResult( request );
}
[HttpGet]
[Route( "GetBusinessCount" )]
public int GetBusinessCount()
{
return db.Businesses.Count();
}
}
Turns out the issue was less on the client side, I got this to work using the above methods but my using the following on the APIController side of things to correctly parse out the query values. This is very poorly documented by the Telerik team.
public DataSourceResult Get( [ModelBinder( typeof( WebApiDataSourceRequestModelBinder ) )] DataSourceRequest request)
I have a server side class:TopicsListModel
with properties as follows:
public class TopicsListModel
{
public TopicsListModel()
{
ChildTopics = new HashSet<TopicsListModel>();
}
public int Id { get; set; }
public string Name { get; set; }
public ICollection<TopicsListModel> ChildTopics { get; set; }
}
There is a function which returns a List,
public JsonResult SearchTopic(String topic)
{
var topics = LandingManager.SearchTopics(topic);
//return Json(topics);
return new JsonResult { Data = topic, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
I need to add this to the Backbone model and collection. I am a newbie to Backbone and I am struggling as you can guess. Any help would be greatly appreciated.
I want to build a model which will store data like:
{ name: "Model1", id: 1, submodels: [{ name: "Submodel1", id: 2 }, { name: "Submodel1", id: 2 }] }
I am unable to do so, I am having trouble setting up the basic collection like that, the ASP.NET MVC code part which returns the data I have shared. Sharing whatever I have done in the Backbone:
TestBB = function () {
if (!window.console) window.console = { log: function () { } };
var treeModel = Backbone.Model.extend({});
var treeSubModel = Backbone.Model.extend({});
var treeCollection = Backbone.Collection.extend({
model: treeSubModel,
initialize: function () {
console.log('Collection Initialized');
}
});
var treeView = Backbone.View.extend({
el: $('#tree-view'),
initialize: function () {
// this.collection.bind("render", this.render, this);
// this.collection.bind("addAll", this.addAll, this);
// this.collection.bind("addOne", this.addOne, this);
_.bindAll(this);
},
render: function () {
console.log("render");
console.log(this.collection.length);
$(this.el).html(this.template());
this.addAll();
var template = _.template($("#template").html(), {});
this.el.html(template);
},
addAll: function () {
console.log("addAll");
this.collection.each(this.addOne);
},
addOne: function (model) {
console.log("addOne");
view = new treeView({ model: model });
$("ul", this.el).append(view.render());
},
events: { "click #btnFind": "doFind" },
doFind: function (event) { alert('event fired'); }
});
return {
TreeView: treeView
};} (Backbone);
Please suggest.
It isn't a case of 'binding' the collection to the back-end, as such: you fetch a collection from the server to read, and save (via sync) to write.
Firstly you'll need to let the collection know where the data resides by setting the url property. See: http://backbonejs.org/#Collection-url.
Secondly you'll need to actually retrieve the data using the fetch method. See http://backbonejs.org/#Collection-fetch. Note this is asynchronous, so you'll need to wait for the success callback.
To save data, use the save method on individual models. See http://backbonejs.org/#Model-save.
Solved
I figured out the approach and defined the model and populated it!