Reputation: 2589
I have a method where I am trying to add a child to my parent, but when the call is made to the method, the context of the calling parent is undefined.
The code (abbreviated for clarity) Fiddle http://jsfiddle.net/poundingCode/THghy/
// Initialized the namespace
var my = {};
my.models = {};
// View model declaration
my.vm = (function (model) {
var memberVm = {
id: ko.observable(model.Id),
company: ko.observable(model.Company),
fName: ko.observable(model.FName),
lName: ko.observable(model.LName),
name: ko.observable(model.Name),
positions: ko.observableArray([]),
totalPositions: ko.observable(),
totalProjects: ko.observable()
};
// children
memberVm.loadPositions = function (positions) {
memberVm.totalPositions = 0;
memberVm.totalProjects = 0;
$.each(positions, function (i, p) {
memberVm.positions.push( new my.models.Position()
.company(p.Company)
.companyId(p.CompanyId)
.description(p.Description)
.id(p.Id)
.memberId(p.MemberId)
.name(p.Name)
.title(p.Title)
.projects(p.Projects)
);
memberVm.totalPositions++;
memberVm.totalProjects += p.Projects.length;
});// end for each
}; //end load positions
memberVm.loadPositions(model.Positions);
memberVm.fullName = ko.computed(function () {
return this.fName() + ' ' + this.lName();
}, memberVm);
// Computed observable function.
// We append it to the ViewModel here.
// return object
var vm = {
id: memberVm.id,
company: memberVm.company,
fName: memberVm.fName,
fullName: memberVm.fullName,
lName: memberVm.lName,
name: memberVm.name,
positions: memberVm.positions,
totalPositions: memberVm.totalPositions,
totalProjects: memberVm.totalProjects,
};
return vm;
});
/////////////////////////////////////
// Add a position - or at least try to! this is where I get into trouble.
my.vm.addPosition = (function () {
var pos = new my.models.Position();
pos.memberId = my.vm.id;
my.vm.positions.push(pos);
});
/////////////////////////////////////
// TypeError: my.vm.positions is undefined my.vm.positions.push(pos);
my.models.Member = (function () {
id = ko.observable();
company = ko.observable();
fName = ko.observable();
lName = ko.observable();
name = ko.observable();
positions = ko.observableArray([]);
});
my.models.Position = (function () {
this.company = ko.observable();
this.id = ko.observable();
this.memberId = ko.observable();
this.name = ko.observable();
this.title = ko.observable();
// place holders
this.totalProjects = ko.observableArray();
this.totalCredits = ko.observableArray();
});
var viewModel = my.vm(data);
ko.applyBindings(viewModel);
my.setUI();
The HTML
<script type="text/html" id="positionItemTemplate">
<div class="summary" data-bind="attr : {onClick: 'my.showDetails(' + id() + ')', href: '#detail_'+ id()}">
<a data-bind="attr : { href: '#detail_'+ id()}">
<h2><label data-bind="text: company().Name"></label>: <label data-bind="text: title"></label></h2> </a>
<h3><label data-bind="text: title" ></label> <label data-bind="text: startDate" ></label> - <label data-bind="value: endDate" ></label></h3>
</div>
<div data-bind="attr : {id: 'detail_' + id() }" class="details" style="right: 580px;">
<div class="positionOverview">
<h2><label data-bind="text: company().Name"></label>: <label data-bind="text: title"></label></h2> </a>
<a data-bind="attr : {href: '#detail_'+ id()}"> <div class="editor-label"><label>Position</label></div></a>
<div class="editor-field">
<input type="text" data-bind="value: company().Name" class="textbox-long">
</div>
<div class="editor-label">
<label>Title</label>
</div>
<div class="editor-field">
<input type="text" data-bind="value: title" class="textbox-long">
</div>
<div class="editor-label">
<label>Summary</label>
</div>
<div class="editor-field">
<textarea data-bind="value: summary" rows="4" cols="60"></textarea>
</div>
<div class="editor-label"><label>Compensation</label></div>
<div class="editor-field">
<select data-bind="options: $parent.compensations, value: compensationId, optionsText: 'Name', optionsValue: 'Id', optionsCaption: 'Select'"></select>
</div>
<div class="editor-label"><label for="HoursPerWeek" class="hourly">Hours/Week</label></div>
<div class="editor-field">
<input type="text" data-bind="value: hoursPerWeek" class="number-short">
</div>
<div class="div-table">
<div class="div-table-row">
<div class="div-table-col"><label for="StartDate">Start Date</label></div>
<div class="div-table-col"><label for="EndDate">End Date</label></div>
<div class="div-table-col"></div>
</div>
<div class="div-table-row">
<div class="div-table-col"><input type="text" data-bind="value: startDate" class="date"></div>
<div class="div-table-col"><input type="text" data-bind="value: endDate" class="date"></div>
</div>
<div class="div-table-row salary">
<div class="div-table-col"><label for="SalaryStart">$/Hr Start</label></div>
<div class="div-table-col"><label for="SalaryStart">$/Hr End</label></div>
</div>
<div class="div-table-row salary">
<div class="div-table-col"><input type="text" data-bind="value: salaryStart" class="date"></div>
<div class="div-table-col"><input type="text" data-bind="value: salaryEnd" class="date"></div>
</div>
</div>
<input id="btnAddProject" type="button" value="Add Project" data-bind="attr : {onClick: 'addProject(new project())'}">
<input type="button" data-bind="attr : {onClick: 'my.showDetails(' + id() + ')'}" value="Update"/>
</div>
</div>
</script>
</head>
<body>
<div id="main">
<div class="marquee center">
<aside class="aside">
<div class="display">
<label data-bind="text: 'Total Positions: ' + totalPositions" ></label><input value="Add Position" type="button" data-bind="attr : {onClick: 'my.vm.addPosition()'}"/><br />
</div>
<div class="adPanel">
<h4><div id="message"></div></h4>
</div>
</aside>
</div>
<section id="primary" class="primary">
<article id="article1">
<section >
<div id="positions">
<div class="position" data-bind="template: { name: 'positionItemTemplate', foreach: positions, as: 'position' }">
</div>
</div>
</section>
</article>
<!-- <footer class="footer">
<p>Copyright © 2008 All Rights</p>
</footer>-->
</section>
</div>
</body>
</html>
Upvotes: 1
Views: 204
Reputation: 114792
The main issue is that your my.vm
is a constructor function that you can use to create an instance of a my.vm
. However, the addPosition
function was added directly to my.vm
and tries to push to my.vm.positions
.
Ideally what you want to do is make the function available on an instance of your vm and push to that instance's positions
array.
So, you would put addPosition
inside your vm declaration and have it operate on the vm
variable that you are returning. At that point your bindings run into issues when you add a new position, as company
is empty and some of the bindings refer to company().Name
Upvotes: 2