So in my PhoneJS web app, I have a dxList widget, with checkboxes on each item. I want to be able to select multiple items, and then do something with them. I'm trying to bind the 'checked' binding to an observable, but I get an 'undefined' error.
Here's the code for the dxTemplate for the list
<div data-options="dxTemplate:{name:'item'}">
<span data-bind="text: $data.information"></span>
<div data-bind="dxCheckBox: { checked: check_boxes }"></div>
</div>
The problem is that check_boxes is in the viewModel, not the item array. I need to access values in the viewModel. I've tried viewModel.check_boxes, but with no success.
Here's the js code:
AppNamespace.otherView = function (params) {
var viewModel = {
my_list: [
{
key: 'Group 1',
items: [
{ information: 'Test 1' },
{ information: 'Test 2'},
{ information: 'Test 3' }
]
}
],
check_boxes: ko.observable(false),
//...etc
Has anyone had any experience with this, and is there a solution?
Thanks!
Knockout provides special properties to access parent binding contexts. In your case both $parent and $root should work.
More on this topic in Knockout docs: Binding context.
Related
I am using jquery datatable in asp.net mvc and i want to show a submit button which will be saving the data to the database only if there is atleast one row in the datatable.
I am trying this code, however its not working
<tr id="trbtnSubmit">
<td colspan="9" align="center">
<input type="submit" name="btnSubmit" value="Save"
class="btn btn-edit btn-text" />
</td>
</tr>
<script>
var PopUp, dataTable;
$(document).ready(function () {
dataTable = $("#tblCustomerList").DataTable({
"ajax": {
"url": "/Customer/GetCustomers",
"type": "GET",
"data": "json"
},
"lengthChange": false,
"pageLength": 10,
"columns": [
{ "data": "Number" },
{ "data": "Name" },
{ "data": "fileName" },
{ "data": "mD5Hash" },
{ "data": "dataSizeInGB" },
{
"data": "Id",
"render": function () {
return "<a href='#'><i class='fa fa-eye'></a></i><a href='#' style='margin-left:5px'><i class='fa fa-pencil'></i></a><a href='#' style='margin-left:5px'><i class='fa fa-trash'></a></i>";
},
"orderable": false,
"width": "40px"
},
],
"language": {
"emptyTable": "No Customers , click on <b>New Customer</b> to add Customers"
}
});
var table = $('#tblCustomerList').DataTable();
if (!table.data().any()) {
$('#trbtnSubmit').hide();
} else {
$('#trbtnSubmit').show();
}
});
</script>
Since you didn't specify the version of datatables, I assume it's v1.10.
And there are 2 side notes I want to make before going into your problem:
Difference between .datatable() and .DataTable()
Enable server-side processing
Difference Between .datatable() and .DataTable()
I saw you declared another variable, var table, at the bottom of your sample code to get another instance of DataTables and check if there is any data? You actually don't need to.
.DataTable() returns a DataTables API instance, while .datatable() returns a jQuery object.
So if you intent to make usages on the DataTables APIs after you initialize the table, you can just use the varirable you declared from the beginning, var dataTable since you used .DataTable() way.
Enable Server-side Processing
Server-side processing is enabled by turning on the serverSide option, and configuring the ajax option. You're missing the first one, whose default is false.
So you might need to add serverSide option in your code:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
ajax: {
...
},
...
});
Enough said. Now looking at your problem ...
DataTables Callbacks
There are many ways to achieve what you want to do, and I like to use callbacks so that you can configure your DataTables in one place.
There are lots of callbacks you can use, and the one I would use is drawCallback:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
...,
language: {
emptyTable: "No Customers , click on <b>New Customer</b> to add Customers"
},
drawCallback: function(settings) {
$('#trbtnSubmit').toggle(settings.aoData.length > 0);
}
});
Hopefully my code is readable enough without any additional explanations :)
I have a JSON object like the following:
{
"sessions": [
{
"title": Session Title,
"room": "Ballroom A"
},
{
"title": Session Title #2,
"room": "Ballroom B"
}
],
"speakers": [
{
"name": John Doe,
"twitter": "jdoe"
},
{
"name": John Smith,
"twitter": "jsmith"
}
]
}
I am trying to bind to the sessions child of the object. The full object is in a variable named conferenceData and the code I am using to display the titles is:
<div *ngFor="#session of conferenceData.sessions">{{session.title}}</div>
When I do this, I get the error: TypeError:
Cannot read property 'sessions' of undefined in [conferenceData.sessions in ProductListComponent#65:17]
If I assign the child to a variable:
this.sessionData = this.conferenceData.sessions;
Then bind to the sessionData variable instead, it works as expected. This is using TypeScript and Angular 2. I suppose this could be a type issue with TypeScript, but I thought by this time it was all JavaScript. Any help would be appreciated.
Thanks!
This is probably, because this.conferenceData is not assigned yet, when Angular is rendering your view the first time.
You can easily fix this with the elvis operator:
<div *ngFor="#session of conferenceData?.sessions">{{session.title}}</div>
The problem is the time to fetch the json data, the component doesn't have the data when the angular renders the view. The solution is uses 'elvis' (?) operator to ensure the data is ready:
-
<div *ngFor="#session of conferenceData?.sessions">
{{session.title}}
</div>
The second solution is hide the ngFor until the conferenceData is ready:
<div *ngIf="conferenceData">
<div *ngFor="#session of conferenceData.sessions">
{{session.title}}
</div>
</div>
The Problem
I have a Rails 4 backed Ember app that needs to iterate over some children, and then iterate over that child's children. The setup is Session -> hasMany -> Annotations -> hasMany -> Indicators.
I can load the /session/1 show template and display the session's properties. I can also iterate over my session's annotations and display the annotation's text. However When I iterate over the annotation's indicators, nothing shows up. If I output {{#with annotation}}{{indicators}}{{/with}} I just get <DS.PromiseArray:ember802>
Ember makes AJAX calls to /sessions/1 and /annotations?ids%5B%5D=113&ids%5B%5D=112. However it never makes a call to /indicators.
I've seen other posts that describe the same issue, but the solutions for those often came down to camel casing etc. In this case, since /indicators is never even being called, what am I doing wrong?
Environment
ember.js - 1.5.1
ember-data.js - 1.0.0-beta.7
Written in CoffeeScript
Ember Setup
Insight.ApplicationAdapter = DS.ActiveModelAdapter.extend({})
Insight.ApplicationSerializer = DS.ActiveModelSerializer.extend({})
Models
App.Indicator = DS.Model.extend {
title: DS.attr 'string'
}
App.Annotation = DS.Model.extend {
text: DS.attr 'string'
session: DS.belongsTo 'session', inverse: 'annotations'
indicators: DS.hasMany 'indicator', async: true
}
App.Session = DS.Model.extend {
subject: DS.attr 'string'
students: DS.attr 'number'
time: DS.attr 'string'
annotations: DS.hasMany 'annotation', async: true
}
Routes
App.SessionRoute = Ember.Route.extend {
model: (params)->
return #store.find('session', params.session_id)`
Session Show Template (Relevant Portion)
<section class='content'>
{{#each annotation in annotations itemController="annotation"}}
{{#with annotation}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{edit-annotation class="edit" value=bufferedText focus-out="doneEditing" insert-newline="doneEditing" escape-press="cancelEditing"}}
{{else}}
{{text}}
</div>
{{/if}}
{{#each indicator in indicators}}
<button>{{indicator.title}}</button>
{{/each}}
</li>
{{/with}}
{{/each}}
{{view Ember.TextField id="new-annotation" placeholder="Enter an annotation" valueBinding="newAnnotation" action="createAnnotation"}}
</section>
JSON GET Payloads
{"session":{
"id":4,
"subject":"Name of Subject",
"students":1,
"time":"08:52",
"annotations":[113,112]}
}
{"annotations":
[
{ "id":112,
"text":"this is my first annotation",
"session":4,
"indicators":[1]
},
{ "id":113,
"text":"This annotation has indicators",
"session":4,
"team_member":8,
"indicators":[1,2]
}
]
}
The problem lies in JSON format.
Format that you're using is the format that is accepted by the RESTAdapter
data: [
title: "Some Title",
items: [1,2]
]
ActiveModelAdapter however expects the data to be in this format:
data: [
title: "Some Title",
item_ids: [1,2]
]
To solve the problem you can either swap to RESTAdapter OR change the data producer to produce proper format instead.
JSBin with above code made working and
other question that reference the same issue.
Hypothetical example to illustrate a problem I am having using angular-UI select2. Let's say I have a screen where I want to edit a "game" model. A game, among other things has players. I want to be able to set the players via a select2 drop down menu. Here's some example code:
app.js
$scope.getGamePromise().then(function(results) {
$scope.game = results;
console.log(game.players); //prints [{name:'Joe',age: 15},{name:'Sally',age:16}]
});
$scope.players = [
{
name: 'Joe',
age: 15
},
{
name: 'Fred',
age: 14
},
{
name: 'Sally',
age: 16
},
{
name: 'Lucy',
age: 13
}
]
view.html
<select ngModel="game.players" ui-select2 multiple>
<option ng-repeat="player in players" value="player">{{ player.name }}</option>
</select>
When I want to save this 'game' object, I send the game object up to the server. The server is expecting game.players to be an array of objects. However, what is being sent up is a string. I am moderately familiar with angular, and completely new to select2. How can I get my select2 to set game.players as an array of objects instead of strings?
I guess you find another solution or you don't have the problem anymore. Anyway I post it here:
Use
<input>
instead of
<select>
Example:
<input type="hidden" ui-select2="playersCfg" ng-model="players"/>
And following configuration:
$scope.playersCfg = {
multiple: true,
allowClear: true,
data: { results: Player.query(), text: 'name' },
formatResult: function(item) {
return "<div class='select2-user-result'>" + item.name + "</div>";
},
formatSelection: function(item) {
return item.name;
}
};
Player.query()
is a resource which returns a list of player containing a name (name) and an identifier (id)
Hope it would help somebody!
I am working on asp.net mvc with Kendo UI mvc. I have two kendo dropdown lists. one for list of clinics and another of list of patients in selected clinic. But there is no direct relationship between clinic and patient to use the cascading dropdownlist. for that i have used ajax calls in dropdownlist change event and get list of patients. and this is my first dropdownlist for list clinics
#(
Html.Kendo().DropDownList()
.Name("ddlClinics")
.Events(e=>e.Change("ChangeClinic"))
.BindTo(new SelectList((List<Account.Entities.Clinic>)ViewBag.lstClinic,
"ClinicID", "ClinicName")))
and this is my second dropdownlist for listpatients
#(
Html.Kendo().DropDownList()
.Name("ddlPatients")
.BindTo(new SelectList((List<Patient>)ViewBag.Patients,
"PatId", "PatName"))))
I want to dynamically bind the list of patients to second dropdownlist when the first dropdownlist changes,
function ChangeClinic()
{
$.ajax({
url: '/Messages/GetPatient',
type: 'Post',
data: { email: '#User.Identity.Name' },
cache: false,
success: function (result) {
var ddlPatients = $('#ddlPatients').data('kendoDropDownList');
var main = [];
$.each(result, function (k, v) {
main.push({ "PatId": v.PatId, "PatName": v.PatName });
});
ddlPatients.dataTextField = "PatName";
ddlPatients.dataValueField = "PatId";
ddlPatients.dataSource.data(main);
ddlPatients.reload();
}
});
}
i am able to bind the list to dropdownlist but all items are shows as 'undefined'. so please guide me.
From what I can tell, there is a relationship between clinics and patients so you should be able to use the CascadeFrom("DropDownList1") provided in the wrappers. We use a cascading dropdownlist in a similar fashion for the relationship between school districts and schools:
#(Html.Kendo().DropDownList()
.Name("District")
.HtmlAttributes(new { style = "width:300px;" })
.BindTo(ViewBag.districts)
.DataTextField("DistrictName")
.DataValueField("DistrictID")
.OptionLabel("Select District")
)
#(Html.Kendo().DropDownList()
.Name("School")
.HtmlAttributes(new { style = "width:300px;" })
.CascadeFrom("District")
.BindTo(ViewBag.schools)
.DataTextField("SchoolName")
.DataValueField("SchoolID")
.OptionLabel("Select School")
)
If you want fill second DropDown on basis of first DropDown value.
Telerik Provided,
.CascadeTo("DropDownList2")
Please see following link for detailed information.
Cascading of Dropdown in Telerik dropdownlist
Instead of creating such array which is useless to the dataSource use:
success: function (result) {
var ddlPatients = $('#ddlPatients').data('kendoDropDownList');
var main = [];
$.each(result, function (k, v) {
main.push({ "text": v.PatId, "value": v.PatName });
});
ddlPatients.dataSource.data(main);
}
});
If you are not using
.DataSource(source =>
{
source.Read(read =>
{
read.Action ("FunctionName", "ControllerName").Data("filterDropdown1");
}).ServerFiltering(true);
})
.CascadeFrom("Dropdown1")
properties in the definition of second dropdown and you are using the definition mentioned in question above. i.e:-
#(
Html.Kendo().DropDownList()
.Name("ddlPatients")
.BindTo(new SelectList((List<Patient>)ViewBag.Patients,"PatId", "PatName"))
)
then you can bind the data to the 2nd dropdown directly in the success function of ajax post.
function ChangeClinic()
{
$.ajax({
url: '/Messages/GetPatient',
type: 'Post',
data: { email: '#User.Identity.Name' },
cache: false,
success: function (result) {
$('#ddlPatients').data('kendoDropDownList').dataSource.data(result);
//ddlPatients.reload();
}
});
}
#Note:- 1) The result value should contain the list of new patients with properties "PatId" and "PatName" based on the parameter email passed to the function "Messages" in GetPatient controller, and there will be no need for ddlpatients.reload(), infact .reload() is not supported, it will break the execution, so don't use .reload().