knockout.js - data-bind subitems within list - dom

Given the the gracious example given to me on this page:
knockout.js - modify DOM in current item in list (expand list item subsection) using templates
I'd like to add a list of sub items called "JobNotes" inside of each job. Let's say for now the JobNote has a structure of "Id" and "Text". How would I databind a list of subitems in my list of jobs?
Thanks.

The answer to this question can be found on this jsFiddle
http://jsfiddle.net/R4Gnw/21/
<div data-bind="foreach: jobs">
<div>
<div class="jobContainer">
<label data-bind="text: data.JobTitle"></label>
<l`enter code here`abel data-bind="text: data.CompanyName"></label>
<div class="jobDetails" data-bind="visible: expanded">
<label data-bind="text: data.CityName"></label>
<label data-bind="text: data.JobIndustry"></label>
<div data-bind="foreach: notes">
<label data-bind="text: text"></label>
Remove
</div>
</div>
<div>
Expand
Add Note
</div>
</div>
​var json = [
{
"JobTitle": "Investment Banking Associate",
"CompanyName": "Value Line Consulting",
"CityName": "Sydney - Australia",
"JobIndustry": "Consulting - General",
"JobNotes": [
{
"Id": 4,
"JobId": 1474,
"Text": "A test Note!"}
],
"Id": 1474}
]
function JobNote(data) {
this.text= data.Text;
}
function Job(data) {
var self = this;
this.data = data;
this.notes = ko.observableArray([]);
// new JobNote("note1"),
// new JobNote("note2"),
// ]);
var mappedNotes = $.map(data.JobNotes, function(item) { return new JobNote(item) });
this.notes(mappedNotes);
this.someValue = ko.observable().extend({
defaultIfNull: "some default"
});
this.expanded = ko.observable(false);
this.linkLabel = ko.computed(function() {
return this.expanded() ? "collapse" : "expand";
}, this);
this.deleteNote = function(jobNote) {
self.notes.remove(jobNote);
}
};
var viewModel = function() {
var self = this;
this.jobs = ko.observableArray([
// new Job(json),
// new Job(),
// new Job(),
]);
this.toggle = function(item) {
item.expanded(!item.expanded());
}
this.addNote = function(job) {
job.notes.push(new JobNote("new note"));
}
var mappedJobs = $.map(json, function(item) {
return new Job(item)
});`enter code here`
self.jobs(mappedJobs);
};
ko.applyBindings(new viewModel());​

Related

sending Angular 6 form including checkbox values not working with template driven forms

I'm trying to pass form values including checkboxes in angular 6 forms using formbuilder but I'm unable to read the value from checkbox. I am getting all the values from all the other input fields but only checkbox is not responding Here is my code:
<form [formGroup]="myGroup" (submit)="submit(myGroup.value)">
<div class="row">
<div class="col-sm-4" *ngFor="let info of myGroup.controls['myInfo'].controls; let i = index">
<label for="{{labelValue[i].name}}"> {{labelValue[i].label}}
<input type="{{labelValue[i].type}}" class="{{labelValue[i].class}}" [formControl]="info">
</label>
</div>
</div>
<div class="row">
<button class="form-control btn-sub" type=”submit”>
Submit Details
</button>
</div>
My component class:
import { ProposalService, CustomerDetails, ProposalNumber } from 'src/app/Services/Proposal-service/proposal.service';
export interface InputType{
name:string;
type: string;
label: string;
class:string;
}
export class ProposalComponent implements OnInit {
public labelValue: InputType[] = [
{name:"fname",type:"text",label:"First Name", class:"form-control"},
{name:"form60",type:"checkbox",label:"Is Collection Of form 60", class:"form-control"},
{name:"eia-num",type:"number",label:"EIA Number", class:"form-control"}
];
title = "Customer Details";
details: Observable<CustomerDetails>;
pNumber: ProposalNumber ;
public information: CustomerDetails[] = [
{name:"First Name", value:""},//
{name:"IsCollectionOfform60", value:true},
{name:"EIA Number", value:""}
];
myGroup : FormGroup;
constructor(private formBuilder: FormBuilder,
private _proposalService: ProposalService) { }
ngOnInit() {
this.myGroup = this.formBuilder.group({
myInfo: this.constructFormArray()
});
this.pNumber = <ProposalNumber>{proposalNumber: 0 ,message:"", status: ""};
}
constructFormArray()
{
const arr = this.information.map(cat => {
return this.formBuilder.control(cat.value);
});
return this.formBuilder.array(arr);
}
submit(form){
//this.loading = true;
console.log(form);
let mySelectedAddon = form.myInfo.map((currentValue,i)=> {
return { "name" : this.information[i].name , "value" : currentValue}
}
);
console.log(mySelectedAddon);
this._proposalService.loadCustomer(mySelectedAddon).subscribe((res: ProposalNumber) =>{
//this.loading = false;
console.log(res);
this.pNumber.proposalNumber = res.proposalNumber;
this.pNumber.message = res.message;
console.log(this.pNumber.proposalNumber);
return this.myGroup.value;
});
}
}
You need to use the 'change' event and pass the respective input value and event to a method onChange where you check if it's checked, then add the respective value to the formarray, if it's unchecked, remove the chosen email from the form array.
You can refer the below link:
https://stackblitz.com/edit/angular-rskaug?file=src%2Fapp%2Fapp.component.ts
Above example is useful to get the values of checkbox dynamically.

Knockout event binding with condition

I want to bind some events to an element , using the knockout "event" binding
But I want all of the listed events to be bound only with a specific case.
The viewmodel:
function vm(){
var self = this;
self.isEditMode = ko.observable(false);//can be changed to true
self.events = ko.observable({
down: function () {
console.log("down")
},
up: function () {
console.log("up")
},
hover: function () {
console.log("hover")
}
});
}
and the Html:
<div style="border:1px solid red;width:50px;height:50px"
data-bind="event:{mousedown:events().down,mouseup:events().up,mouseover:events().hover}:null"></div>
<button data-bind="click:function(){isEditMode(!isEditMode())}">change </button>
I tried:
<div data-bind="event:isEditMode()?{mousedown:events().down,mouseup:events().up,mouseover:events().hover}:null"></div>
But it did not work for me.
I think the best way to do it is by using custom bindingHandlers, but I dont know how.
Thank you very much for your help!
You can simplify the the binding by moving some logic into the view model
<div style="border:1px solid red;width:50px;height:50px"
data-bind="event: {
mousedown: down,
mouseup:up,
mouseover:hover }" > </div>
and view model like this
function vm() {
var self = this;
this.isEditMode = ko.observable(true);
down = function() {
if(this.isEditMode())
{
console.log("down")
}
};
up = function() {
if(this.isEditMode())
{
console.log("up")
}
};
hover = function() {
if(this.isEditMode())
{
console.log("hover")
}
};
}
var viewModel = new vm();
ko.applyBindings(viewModel);
Another option is to place the condition in the markup itself as two separate blocks using an "if" binding to determine which ones gets shown and bound.
function vm() {
var self = this;
self.isEditMode = ko.observable(false); //can be changed to true
self.events = ko.observable({
down: function() {
console.log("down");
},
up: function() {
console.log("up");
},
hover: function() {
console.log("hover");
}
});
}
ko.applyBindings(new vm());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<!--ko if: isEditMode()-->
<div style="border:1px solid red;width:50px;height:50px" data-bind="event:{
mousedown:events().down,
mouseup:events().up,
mouseover:events().hover
}">
Edit Mode
</div>
<!--/ko-->
<!--ko if: !isEditMode()-->
<div style="border:1px solid red;width:50px;height:50px">
Read Only
</div>
<!--/ko-->
<button data-bind="click:function(){isEditMode(!isEditMode())}">change </button>

updating text using knockout computed function

In a table I have a checkbox bound to a bool in an observable array.
If any of the checkboxes in the table are checked / unchecked I want to update some text with the total checked.
I cannot get the computed function to fire, I have tried using ko.utils.unwrapObservable on both the array and location.isSelected in the 'if' statement below, am I just using it in the wrong place?
<input type="checkbox" data-bind="checked: isSelected"/>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />
self.totalSelected = ko.computed(function () {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function (location) {
if (location.isSelected == true) {
selected = (+selected) + 1;
}
});
return selected;
}, self).extend({ notify: 'always' });
One of the issues is that isSelected is treated like a variable inside the computed: location.isSelected == true. However, if you intend to bind a checkbox to it, it must be an observable.
So, I have declared a function to create the children of self.SelectedLocations as:
var locationObservable = function() {
var self = this;
self.isSelected = ko.observable(false);
};
Then, you could change the counting in the computed variable as follows:
if (loc.isSelected()) {
selected++;
}
var locationObservable = function(selected) {
var self = this;
self.isSelected = ko.observable(selected);
};
var model = function() {
var self = this;
self.SelectedLocations = ko.observableArray();
self.SelectedLocations.push(new locationObservable(false)); // Set the state of the checkbox here.
self.SelectedLocations.push(new locationObservable(true));
self.SelectedLocations.push(new locationObservable(false));
self.totalSelected = ko.computed(function() {
var selected = 0;
ko.utils.arrayForEach(self.SelectedLocations(), function(loc) {
if (loc.isSelected()) {
selected++;
}
});
return selected;
}, self);
};
var vm = new model();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: SelectedLocations">
<input type="checkbox" data-bind="checked: isSelected" />
</div>
<span class="text-left h5 ">Total Selected:</span><span data-bind="text: totalSelected" />

Kendo Ui Grid not rebinding after search button click

I having difficulty where the Kendo Ui grid would not rebind with new result after the Search button click.Please let me know how i could achieve this. Thank you
Currently the GetList will return data correctly however the KendoUi grid would not rebind with the new result.
.cshtml
<div id="search">
<div>
<div class="searchOption">
#Html.LabelFor(model => model.HRN)
#Html.EditorFor(model => model.HRN)
</div>
</div>
<div>
<div class="smallBox">
<input type="button" id="btnSearch" style="height:32px; font-size:14px; background-color:#3399FF" class="k-button" title="Search" value="Search" />
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.FamilyName)
#Html.EditorFor(model => model.FamilyName)
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.GivenName)
#Html.EditorFor(model => model.GivenName)
</div>
</div>
<div>
<div class="searchOption">
#Html.LabelFor(model => model.Priority)
#Html.EditorFor(model => model.Priority)
</div>
</div>
</div>
#(Html.Kendo().Grid<PWeb_App.ViewModels.ResultModel>()
.Name("Result")
.HtmlAttributes(new { #Style = "align:center; font-size:10px; width:985px" })
.Events(ev => ev.Change("onChange"))
.Columns(columns =>
{
columns.Bound(p => p.GivenName).Width(90);
columns.Bound(p => p.FamilyName).Width(90);
columns.Bound(p => p.Community).Width(130);
})
.ToolBar(toolbar => toolbar.Save())
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Pageable(paging => paging
.Input(false)
.Numeric(true)
.PreviousNext(true)
.PageSizes(new int[] { 5, 10, 25, 50 })
.Refresh(false)
)
.Selectable()
.Scrollable()
.ColumnMenu(c => c.Columns(false))
.DataSource(dataSource => dataSource
.Ajax()//bind with Ajax instead server bind
.PageSize(10)
.ServerOperation(true)
.Model(model =>
{
model.Id(p => p.Pid);
model.Field(p => p.FamilyName).Editable(false);
model.Field(p => p.GivenName).Editable(false);
})
.Read(read => read.Action("GetData", "Details").Type(HttpVerbs.Get))
.Update("Edit", "Details")
)
)
<script type="text/javascript">
$(document).ready(function () {
$('#btnConsumerSearch').click(function (e){
var community = $("#Community").val();
var familyName = $("#FamilyName").val();
var givenName = $("#GivenName").val();
$.ajax({
type: 'POST',
complete: function(e) {
$("#Result").data("kendoGrid").dataSource.read();
},
url: "#(Url.Content("~/Details/GetData/"))",
data: {
"Community":community,
"FamilyName":familyName,
"GivenName":givenName
},
success: function () {
$("#btnSearch").removeAttr('disabled');
}
});
$("#btnSearch").attr('disabled','disabled');
});
});
</script>
controller:
//The following code will return data new result as expected however the kendo grid does not refresh with the result of the following code:
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, SearchCriteria model)
{
DataTable result = GetList(model);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
/// <summary>
/// Get all available List from Client table and return using datatable
/// </summary>
/// <returns></returns>
private DataTable GetList(SearchCriteria model, string ReferralListID)
{
using (PEntities context = new PEntities())
{
string ConnectionString = (context.Connection as EntityConnection).StoreConnection.ConnectionString;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConnectionString);
builder.ConnectTimeout = 2500;
using (SqlConnection con = new SqlConnection(builder.ConnectionString))
{
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
using (SqlCommand cmd = new SqlCommand("spListResults", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("paramCommunity", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.Community) ? (object)model.Community : DBNull.Value;
cmd.Parameters.Add("paramGivenName", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.GivenName) ? (object)model.GivenName : DBNull.Value;
cmd.Parameters.Add("paramFamilyName", SqlDbType.VarChar, 100).Value = !String.IsNullOrEmpty(model.FamilyName) ? (object)model.FamilyName : DBNull.Value;
cmd.Parameters.Add("paramPriority", SqlDbType.VarChar, 10).Value = !String.IsNullOrEmpty(model.Priority) ? (object)model.Priority : DBNull.Value;
adapter.SelectCommand = cmd;
cmd.CommandTimeout = 0;
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
}
}
Try like this,
In your grid read method in view like this
.Read(read => read.Action("GetData", "Details").Data("GetData"))
You button should be Submit Type
<input type="Submit" id="btnSearch" style="height:32px; font-size:14px; background-color:#3399FF" class="k-button" title="Search" value="Search" />
Script
function GetData() {
return {
HRN: $('#HRN').val(),
FamilyName: $('#FamilyName').val(),
GivenName: $('#GivenName').val(),
Priority: $('#Priority').val()
};
}
$(document).ready(function () {
$("#btnSearch").click(function (e) {
$("#Result").data("kendoGrid").dataSource.read();
$("#Result").data("kendoGrid").refresh();
e.preventDefault();
});
});
Controller
public ActionResult GetData([DataSourceRequest] DataSourceRequest request, string HRN, string FamilyName, string GivenName, string Priority)
{
DataTable result = GetList(HRN,FamilyName,GivenName,Priority);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

.each() not working in IE

I want to get all labels inside a div, the blow piece of code works in Firefox and not working IE. Any idea. Thanks in advance.
<div id='discounts'>
<label id="discount1"> discount 1</label>
<label id="discount2"> discount 2 </label>
<input type="text" id="discountmisc" value="" />
</div>
var selectLabels = {
getLabels: function() {
$('#discounts > label').each(function(index, item) {
alert(index + $(item).attr('id'));
});
}
};
selectLabels.getLabels();
Are you wrapped in DOM Ready functions? i.e.
$(function () {
var selectLabels = {
getLabels: function() {
$('#discounts > label').each(function(index, item) {
alert(index + $(item).attr('id'));
});
}
};
selectLabels.getLabels();
});
or alternately:
var selectLabels = {
getLabels: function() {
$('#discounts > label').each(function(index, item) {
alert(index + $(item).attr('id'));
});
}
};
$(selectLabels.getLabels);
or finally (because you don't care about the return value):
var selectLabels = {
getLabels: function() {
$(function () {
$('#discounts > label').each(function(index, item) {
alert(index + $(item).attr('id'));
});
});
}
};
selectLabels.getLabels();
Tell me, and if so, I'll change my answer.