We are using Kendo-Scheduler in an Asp.net application.
We are having a problem getting events to display in the calendar.
When we use Server Binding, we can see the events display in the calendar as expected. We do this in our ViewComponent:
public async Task<IViewComponentResult> InvokeAsync()
{
List<TaskViewModel> myTasks = GetItems();
return View(myTasks); //these events display on the calendar succssfully
}
However, we need to use Ajax Binding. When we do the following, no data is returned to the DataSource. When we look at scheduler_dataBound() for the data, we can see that no data is returned from the controller.
What am I doing wrong in the below? Why is the Server binding working but not the Ajax Binding?
//my.cshtml
#(Html.Kendo().Scheduler<Plantview.Core.ViewModels.TaskViewModel>()
.Name("scheduler")
.Date(new DateTime(2022, 10, 01))
.StartTime(new DateTime(2022, 10, 01, 7, 00, 00))
.Height(600)
.Views(views =>
{
views.MonthView(m => {
m.Selected(true);
m.EventHeight(150);
});
})
.Timezone("Etc/UTC")
.DataSource(d => d
.Model(m =>
{
m.Field(f => f.OwnerID).DefaultValue(1);
m.Field(f => f.Title).DefaultValue("No title");
m.Field(f => f.Description).DefaultValue("no desc");
m.RecurrenceId(f => f.RecurrenceID);
})
.Read("Read", "MyController")
)
.Events(e => {
e.DataBound("scheduler_dataBound");
})
)
<script type="text/javascript">
function scheduler_dataBound(e) {
var data = $("#scheduler").data("kendoScheduler").dataSource;
console.log(data); //Here -> _total=0 and _data has no objects
}
</script>
//My Controller method
public virtual JsonResult Read([DataSourceRequest] DataSourceRequest request)
{
//This is getting called from calendar datasource read
return Json(GetItems().ToDataSourceResult(request)); //Here I am mocking up data
}
//My Mock data
public List<TaskViewModel> GetItems()
{
List<TaskViewModel> list = new List<TaskViewModel>();
list.Add(new TaskViewModel
{
Title = "Event 1",
Start = new DateTime(2022, 10, 1),
End = new DateTime(2022, 10, 1),
Description = "Description 1",
IsAllDay = false,
OwnerID = 1,
TaskID = 1
});
......More data
return list;
}
Related
I'm trying delete data but I'm getting this error:
this.jobPosts.filter is not a function
PostJobIndex.vue file:
deleteJobPost: async function(jobPost) {
if (!window.confirm('Are you sure you want to delete this Job Post?')) {
return;
}
try {
await employerService.deleteJobPost(jobPost.id);
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
console.log(this.jobPosts);
this.$toast.success("Job Post deleted Successfully!");
} catch (error) {
console.log(error);
this.$toast.error(error.response.data.message);
}
},
I had this same issue with my Update method and I beleive it was because I was trying to map through an object or something instead of an array. In the end I used Object.keys(this.jobPosts).map for my update method and it worked:
Object.keys(this.jobPosts).map(jobPost => {
if (jobPost.id == response.data.id) {
for (let key in response.data) {
jobPost[key] = response.data[key];
}
}
});
But when I do this for Update it doesn't work:
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
UPDATED
Here is the code for loading the job posts:
loadJobPosts: async function() {
try {
const response = await employerService.loadJobPosts();
this.jobPosts = response.data;
console.log(this.jobPosts);
} catch (error) {
this.$toast.error('Some error occurred, please refresh!');
}
},
Im using Vuex for state management and I'm using services, that simply contain the axios http requests. That's where this line comes from employerService.loadJobPosts() loadJobPosts() is a function inside my employerService.js file.
I'm also using Laravel for my back end. Here is my JobPostsController.php file:
public function index()
{
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id);
return response()->json($jobPosts, 200);
}
From what I've understood from your code,
this should work for removing jobPost from jobPosts
this.jobPosts = this.jobPosts.filter(obj => {
return obj.id != jobPost.id;
});
I don't know what you're expecting this to do, but it won't do anything useful and will either error or return false for everything.
this.jobPosts = Object.keys(this.jobPosts).filter(obj => {
return obj.id != jobPost.id;
});
filter exists on array types, so I would check where it's getting set and make sure it's an array.
I've included a small snippet in case it's any help.
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: () => {
return {
jobPosts: [],
deleteJobId: 1
};
},
methods: {
getJobPosts() {
this.jobPosts = [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}, {
id: 5
}];
},
deleteJob() {
if (!this.deleteJobId)
return;
this.jobPosts = this.jobPosts.filter(x => x.id !== this.deleteJobId);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button type="button" #click="getJobPosts">Get Jobs</button>
<div>
<button type="button" #click="deleteJob">Delete Job #</button>
<input type="number" v-model.number="deleteJobId" />
</div>
<ul>
<li v-for="jobPost in jobPosts">
Job Post #{{jobPost.id}}
</li>
</ul>
</div>
You have already answered your own question:
in my data() object, I have this jobPosts: [], but in the console it says Object
As for your second question:
I don't know how to return the data as an array
There are similiar topics here on SO.
I am not familiar with Laravel but assuming you have an eloquent model with JobPost in your index-function according to the docs you should use the .toArray-method:
$jobPosts = JobPost::all()->where('user_id', Auth::user()->id).toArray();
When working with plain collections the values method should do the trick of returning an array instead of an object:
$collection = collect([
10 => ['product' => 'Desk', 'price' => 200],
11 => ['product' => 'Desk', 'price' => 200]
]);
$values = $collection->values();
$values->all();
UPDATE
I just realized that your result is just a stringified JSON object that needs to be converted into an array. Just parse it before processing (take out the JSON.parse(...) if you are already taking care of it in your service), return the object properties as an array and you are good to go:)
this.jobPosts = Object.values(JSON.parse(this.jobPosts)).filter(obj => {
return obj.id != jobPost.id;
});
I have the below code in Angular component
export class ScheduleComponent implements OnInit, OnDestroy {
source:any;
connect(dateValue){
this.source = new
EventSource('http://localhost:8080/api/schedbydate?mydate='+dateValue);
this.source.addEventListener('datarec', datarec => {
let schedule: Notification;
this.schedule = JSON.parse(datarex.data);
}, false);
}
ngOnInit() {
this._erdayService.getErday().subscribe((erday) => {
this._date = erday.text();
this._erdayService.currentMessage.subscribe(message => {
this._date = message;
this.connect(this._date);}
, (error) => { console.error('SERVER ERROR: SELECTED DAY'); });}
, (error) => { console.error('SERVER ERROR:getSchedulesByDate()'); });
}
ngOnDestroy() {
this.source.removeEventListener('message', this.message, false);
//this line doesn't work because I can't access enter variable here!
console.log("Server stopped schedule");
}
}
The issue is the this._date is initially loaded erday and UI view is according to erday. Now when I change the this._date to message, the UI view gets changed.
But still the erday data is shown in UI and the UI view fluctuates between erday & message and I'm not able to stop the this.source.addEventListener().
I tried to destroy in ngOnDestroy(),but it is not working.
I even tried this.source.close();.
Can someone help to know how to stop the listener created before calling another listener on same source ?
You subscribe to 2 data sources that emits continuously :
- The first being this._erdayService.currentMessage
- The second is this.source (when you trigger this.connect())
So this._date will change continuously. So you have to decide which data source you want to keep.
Case 1: You want to keep this.source as your data provider:
export class ScheduleComponent implements OnInit, OnDestroy {
source:any;
sourceListenerSubscription$ : Observable<any>;
connect(dateValue){
this.source = new
EventSource('http://localhost:8080/api/schedbydate?mydate='+dateValue);
this.sourceSubscription$ = Observable.fromEvent(this.source, 'datarec').subscribe( datarec => {
let schedule: Notification;
this.schedule = JSON.parse(datarex.data);
}, false);
}
ngOnInit() {
this._erdayService.getErday().subscribe((erday) => {
this._date = erday.text();
// take only one erday message, then listen to your spring server
this._erdayService.currentMessage.take(1).subscribe(message => {
this._date = message;
this.connect(this._date);}
, (error) => { console.error('SERVER ERROR: SELECTED DAY'); });}
, (error) => { console.error('SERVER ERROR:getSchedulesByDate()'); });
}
ngOnDestroy() {
this.source.removeEventListener('message', this.message, false);
//this line doesn't work because I can't access enter variable here!
console.log("Server stopped schedule");
}
}
Case 2: You want to keep erday as your data provider:
export class ScheduleComponent implements OnInit, OnDestroy {
source:any;
sourceListenerSubscription$ : Observable<any>;
connect(dateValue){
this.source = new
EventSource('http://localhost:8080/api/schedbydate?mydate='+dateValue);
// take date once from spring server, and keep erday as data source
this.sourceSubscription$ = Observable.fromEvent(this.source, 'datarec').take(1).subscribe( datarec => {
let schedule: Notification;
this.schedule = JSON.parse(datarex.data);
}, false);
}
ngOnInit() {
this._erdayService.getErday().subscribe((erday) => {
this._date = erday.text();
this._erdayService.currentMessage.subscribe(message => {
this._date = message;
this.connect(this._date);}
, (error) => { console.error('SERVER ERROR: SELECTED DAY'); });}
, (error) => { console.error('SERVER ERROR:getSchedulesByDate()'); });
}
ngOnDestroy() {
this.source.removeEventListener('message', this.message, false);
//this line doesn't work because I can't access enter variable here!
console.log("Server stopped schedule");
}
}
Kendo drop down is empty for some reason and I am not sure, below is all my code
#(Html.Kendo().DropDownList()
.Name("parties")
.HtmlAttributes(new { style = "width: 250px" })
.DataTextField("Name")
.DataValueField("PartyId")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetParties", "Concept");
});
})
)
Controller Call
public JsonResult GetParties([DataSourceRequest] DataSourceRequest request)
{
var parties = MiscAdapter.GetParties().Select(x => new PartyModel
{
Name = x.PartyName,
PartyId = x.PartyId
});
return Json(parties.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
Model
public class PartyModel
{
public int PartyId { get; set; }
public string Name { get; set; }
}
Data returned according to the F12 tools
{"Data":[{"PartyId":1,"Name":"New Democratic Party"},{"PartyId":2,"Name":"Saskatchewan Party"},{"PartyId":3,"Name":"Liberal"},{"PartyId":4,"Name":"Green"},{"PartyId":5,"Name":"Independant"}],"Total":5,"AggregateResults":null,"Errors":null}
The dropdown does not show anything in there even though i cant see anything with the code or returned data.
Please try with the below code snippet. The method you have used its used for grid data binding.
public JsonResult GetParties()
{
List<PartyModel> models = new List<PartyModel>();
models.Add(new PartyModel() { Name = "Name1", PartyId = 1 });
models.Add(new PartyModel() { Name = "Name2", PartyId = 2 });
return Json(models, JsonRequestBehavior.AllowGet);
}
Let me know if any concern.
I trying to implement a cascading down list with editor template i am not sure if kendo support it, i have a grid when in editing move i am trying to filter data base on select data from an editor template
grid is showing availablity time a user can work
e.g column Timefrom, TimeTo, status, could be the following
1.) availablity
2.) Unavailablity
3.) Holiday
availablity have different time template compare to Holiday and unavailablity
e.g
"Early/day" - 07.00 -18.00
"Long day" - 0700 - 22.30
"Late" - 12.00 - 22.00
"Night" - 19.00 - 21.00
"Twilight" - 18.00 - 04.00
Holiday/Unavailablity - half day morning
holiday/Unavailablity - half day afternoon
holiday/Unavailablity - evening
holiday/Unavailablity - whole day
what i want to achive when user click on edit mode, status column have a drop down with [Availablity - Unavilablity - Holiday ] after selecting the option availablity time template will be enable with the respective time template.
example when user click on Holiday drop down in edit mode only these option should be display on availablity Time Template column ("Early/day","Long day","Late","Night","Twilight")
below is a demo code simmilar concept to the main application Thanks
main page
#(Html.Kendo().Grid<Availablity>()
.Name("grid-availablity")
.Columns(columns =>
{
columns.Bound(c => c.Id);
columns.Bound(c => c.TimeFrom);
columns.Bound(c => c.TimeTo);
columns.Bound(c => c.Status);
columns.Bound(c => c.AvailablityTimeTemplate); // only testing purpose
columns.Command(command =>
{
command.Edit();
});
})
.DataSource(databinding => databinding.Ajax().PageSize(10).ServerOperation(false)
.Model(model => model.Id(availablity => availablity.Id))
.Read("GetAvailablityList","Availability")
.Update("Availablity_Update","Availability")
)
)
<script>
function filterTimeTemplate() {
return {
AvailablityTimeTemplate: $("#AvailablityTimeTemplate").val()
};
}
</script>
Editor Template
Status Template
#(Html.Kendo().DropDownList()
.Name("Status")
//.DataTextField("")
//.DataValueField("Id")
.OptionLabel("Change Status")
.BindTo(Enum.GetNames(typeof(Status)).ToList())
)
Time Template
#(Html.Kendo().DropDownList()
.Name("AvailablityTimeTemplate")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Change Time...")
//.DataTextField("")
// .DataValueField("")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadingData", "Availability")
.Data("filterTimeTemplate");
})
.ServerFiltering(true);
})
.Enable(false)
.AutoBind(false)
.CascadeFrom("Status")
)
classes and enum
public class Availablity
{
public string Id { get; set; }
public string TimeFrom { get; set; }
public string TimeTo { get; set; }
[UIHint("AvailablityStatus")]
public Status Status { get; set; }
[UIHint("TimeTemplate")]
public string AvailablityTimeTemplate { get; set; }
public List<Availablity> GetAvailablity()
{
return new List<Availablity>()
{
new Availablity(){ Id="001", TimeFrom="0700", TimeTo="18.00", Status=Status.Available},
new Availablity(){ Id="002", TimeFrom="0700", TimeTo="23.30", Status=Status.Available},
new Availablity(){ Id="002", TimeFrom="12.00", TimeTo="22.00", Status=Status.Available}
};
}
public List<string> GetTimeTemplateList(Status status)
{
List<string> TimeTemplateCollection = null;
if (status == Status.Available) {
TimeTemplateCollection = new List<string>(){
"Long day","Late","Night","Twilight"
};
} else {
TimeTemplateCollection = new List<string>(){
"Morning Half Day","Afternoon - Half Day ","Night","Whole Day"
};
}
return TimeTemplateCollection;
}
}
public enum Status
{
Available = 0,
UnAvailable = 1,
Holiday = 2
}
controller
public JsonResult GetCascadingData(Status availablityStatus)
{
var availablity = new Availablity();
var data = availablity.GetTimeTemplateList(availablityStatus);
return Json(data, JsonRequestBehavior.AllowGet);
}
public JsonResult GetAvailablityList([DataSourceRequest] DataSourceRequest request)
{
var availablity = new Availablity();
var data = availablity.GetAvailablity();
return Json(data.AsQueryable().ToDataSourceResult(request));
}
As your comment explain further, this is what you need to change
Time Template
#(Html.Kendo().DropDownList()
.Name("AvailablityTimeTemplate")
.HtmlAttributes(new { style = "width:300px" })
.OptionLabel("Change Time...")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadingData", "Availability").Data("filterTimeTemplate");
})
.ServerFiltering(true);
})
//.Enable(false) should be removed
.AutoBind(false)
.CascadeFrom("Status")
)
I am facing an issue with Kendo grid inline editing, The issue is even though I update any row, 1st row data is displayed in grid, Any help on this?
Before update
After update.
Interestingly the object I return from the controller does have the correct data
Controller code
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
[ActionSessionState(System.Web.SessionState.SessionStateBehavior.Required)]
[OutputCache(Duration = 0, VaryByParam = "none")]
public ActionResult _SaveBatchEditingintegrate([DataSourceRequest] DataSourceRequest request)
{
var UPObj = SessionFacade.UserProfile as UserProfile;
try
{
IntegrationRate objInteg = new IntegrationRate();
TryUpdateModel(objInteg);
if (objInteg.PeriodID != 0)
{
var Integrationrate = (from p in _draftManagecompany.IntegrationRates where p.PeriodID == objInteg.PeriodID select p).First();
TryUpdateModel(Integrationrate);
if (Integrationrate.Rate > 100) //set 100 as default
{
Integrationrate.Rate = 100;
}
}
LoadResourceJSArray();
}
catch (Exception ex)
{
// Adding related additional information along with exception object
//ExceptionLogger.Log(ex, "Period ID", id);
ExceptionLogger.Log(ex, "User Profile Info", UPObj);
// Handle exception with BubbleExceptionPolicy
if (exManager.HandleException(ex, "BubbleExceptionPolicy"))
throw; // Not to include the ex, as the previous stack trace to be maintained
}
//_draftManagecompany.IntegrationRates contains updated value in the correct order
return Json(_draftManagecompany.IntegrationRates.ToDataSourceResult(request));
}
cshtml code:
#{ var integrateGrid = Html.Kendo()
.Grid(Model.Company.IntegrationRates)
.Name("Gridintegrate")
.EnableCustomBinding(true) // Enable custom binding
.BindTo(Model.Company.IntegrationRates)
.Events(events =>
{
events.Change("DataBound_Integ");
})
.ToolBar(
commands =>
{
//commands.Insert().ButtonType(GridButtonType.BareImage).ImageHtmlAttributes(new { style = "visibility:hidden" });
}
)
.Columns(columns =>
{
columns.Bound(p => p.PeriodID).Visible(false);
columns.Bound(p => p.Month).Width(150);
columns.Bound(p => p.Rate).Format("{0:0.00}%").Width(100);
columns.Command(commands =>
{
commands.Edit().HtmlAttributes(new { #id = "btn_IntRateEdit" });
}).Width(150).Title(gridTitle);
})
.HtmlAttributes(new { style = "height: 380px;" })
.Scrollable()
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource.Ajax()
//.Batch(true)
.Read(read => read.Action("_AjaxBindingintegrate", "Company"))
.Update(update => update.Action("_SaveBatchEditingintegrate", "Company"))
.Model(model =>
{
model.Id(c => c.PeriodID);
model.Field(c => c.Month).Editable(false);
}
)
.Events(events =>
{
events.Error("CheckSessionExistsOnTelerik");
})
);
//.Pageable(paging => paging.Style(GridPagerStyles.NextPreviousAndNumeric | GridPagerStyles.PageSizeDropDown).PageSize(20, new int[3] { 20, 50, 100 })).ToComponent();
var culture = System.Globalization.CultureInfo.InvariantCulture;
//integrateGrid.Localization = new GridControlLocalization(culture);
integrateGrid.Render();
}
I think I see the problem here. From what I can tell when you complete the update you are returning the entire data set back on the update ie June, january, February etc.
On the update all you have to do is return the item you have updated back to the grid
So in your example change the return json to the following:
Return json(new { IntegrationRate}.toDataSourceResult(request,modelState),jsonbehaviour.allowget);
This then should sort out your issue.
Because you are returning the entire data set back it is rendering the first row as the expected result.
As you say you see the data saving correctly behind the scenes. So you know an error is not being thrown.