Let's say I have three objects like this:
var registryEpisode = function() {
var self = this;
self.registry = ko.observable(new registry());
self.episodeType = ko.observable(new episodeType());
};
var episodeType = function() {
var self = this;
self.id = ko.observable(""),
self.name = ko.observable("");
};
var registry = function() {
var self = this;
self.id = ko.observable(""),
self.name = ko.observable("");
};
Then I have a view model like this:
var vm = function() {
var self = this;
self.registryEpisodeTypes = ko.observableArray([new registryEpisode()]);
self.addRegistryEpisodeType = function (episodeType, registry) {
var regEpisode = new registryEpisode();
regEpisode.registry = registry;
regEpisode.episodeType = episodeType;
self.registryEpisodeTypes.push(regEpisode);
} .bind(this);
}
I'm trying to bind the view model to a table of dropdown lists and have the view model updated each time a registry and episode type is selected, but I need to maintain the relationship between episodesTypes and registries. Thoughts?
Here is a simple implemantion of a chain dropDownLists: jsFiddle
var registryEpisode = function() {
var self = this;
self.registry = ko.observable(new registry());
self.episodeType = ko.observable(new episodeType());
};
var episodeType = function(id, name) {
var self = this;
self.id = ko.observable(id), self.name = ko.observable(name);
};
var registry = function() {
var self = this;
self.id = ko.observable(""), self.name = ko.observable("");
};
var vm = function() {
var self = this;
self.selectedRegistry = ko.observable("");
self.registryEpisodeTypes = ko.observableArray([]);
self.addRegistryEpisodeType = function(episodeType, registry) {
var regEpisode = new registryEpisode();
regEpisode.registry = registry;
regEpisode.episodeType = episodeType;
self.registryEpisodeTypes.push(regEpisode);
}.bind(this);
self.getRegistries = function() {
var hashCheck = {};
var result = ko.observableArray([]);
ko.utils.arrayMap(self.registryEpisodeTypes(), function(item) {
if (hashCheck["" + item.registry.id()] === null || hashCheck["" + item.registry.id()] === undefined) {
hashCheck["" + item.registry.id()] = item.registry.name();
result.push({
"name": item.registry.name(),
"value": item.registry.id()
});
}
});
return result;
}
self.getEpisodes = ko.dependentObservable(function() {
var ret = self.registryEpisodeTypes();
var selectedRegistryItem = self.selectedRegistry();
if (selectedRegistryItem === null || selectedRegistryItem === undefined || selectedRegistryItem === "")
return ;
var result = ko.observableArray([]);
ko.utils.arrayMap(ret, function(item) {
if (item.registry.id() == selectedRegistryItem) result.push({
"name": item.episodeType.name(),
"value": item.episodeType.id()
});
});
console.log(ko.toJSON(result));
return result;
});
}
var viewModel = new vm();
var breakingBad = new registry();
breakingBad.id("1000");
breakingBad.name("Breaking Bad");
viewModel.addRegistryEpisodeType(new episodeType("1", "E1-breakingBad"), breakingBad);
viewModel.addRegistryEpisodeType(new episodeType("2", "E2-breakingBad"), breakingBad);
viewModel.addRegistryEpisodeType(new episodeType("3", "E3-breakingBad"), breakingBad);
var trueBlood = new registry();
trueBlood.id("1001");
trueBlood.name("True Blood");
viewModel.addRegistryEpisodeType(new episodeType("1", "E1-trueBlood"), trueBlood);
viewModel.addRegistryEpisodeType(new episodeType("2", "E2-trueBlood"), trueBlood);
viewModel.addRegistryEpisodeType(new episodeType("3", "E3-trueBlood"), trueBlood);
ko.applyBindings(viewModel);
<div>
<span data-bind="text:selectedRegistry"></span>
</div>
<div>
<select data-bind="options:getRegistries(),optionsText:'name',optionsValue:'value',value:selectedRegistry"></select>
</div>
<div>
<select data-bind="options:getEpisodes(),optionsText:'name',optionsValue:'value'"></select>
</div>
I create a dependentObservable called getEpisodes. Whenever selectedRegistry changes this episodeList calculated again.
Related
How can I programmatically assign knockout js attributes to a view model?
I need some kind of factory structure, but I'm not sure about the best way to go about it...
I'm trying to assign attributes that don't exist yet to a model..
I want to reduce this:
function aViewModel() {
var self = this;
self.attr1Text = ko.observable("");
self.attr1Text.focused = ko.observable(false);
self.attr2Text = ko.observable("");
self.attr2Text.focused = ko.observable(false);
self.attr3Text = ko.observable("");
self.attr3Text.focused = ko.observable(false);
self.attr4Text = ko.observable("");
self.attr4Text.focused = ko.observable(false);
self.attr5Text = ko.observable("");
self.attr5Text.focused = ko.observable(false);
}
vm = new aViewModel();
ko.applyBindings(vm);
to something like this:
function aViewModel(attrs) {
var self = this;
for (var attr of attrs){
self[attr+"Text"] = ko.observable("");
self[attr+"Text"]["focused"] = ko.observable(false);
}
}
attr_list = ["attr1", "attr2", ..., "attrN"]
vm = new aViewModel(attr_list);
ko.applyBindings(vm);
And have it actually work.
This works:
function aViewModel() {
var self = this;
}
vm = new aViewModel();
attr_list = ["attr1", "attr2", ..., "attrN"]
for (var attr of attr_list){
self[attr+"Text"] = ko.observable("");
self[attr+"Text"]["focused"] = ko.observable(false);
}
ko.applyBindings(vm);
But more encapsulation would be nice so I just created a wrapper function,
function createGrid(things, data){
vm = new gridViewModel(things);
for (var thing of things){
vm[thing+"Text"] = ko.observable("");
vm[thing+"Text"]["focused"] = ko.observable(false);
}
\\ other stuff with data
return vm;
}
then used
vm = createGrid(things, data)
ko.applyBindings(vm);
I feel like I'm answering my own question. But is there a better way to do this?
use the knockout mapping plugin
var modelClass = function(data){
ko.mapping.fromJS(data,this);
//additional values or computed
this.full_name = ko.computed(function(){
return ko.unwrap(this.first_name) + ' ' + ko.unwrap(this.last_name);
}
}
var mapping = {
create : function(options){
return new modelClass(options.data);
}
}
var viewModel = function(){
this.myModel = ko.mapping.fromJS(data,mapping);
}
I have a view model called ProductsViewModel
This contains an observableArray of ProductViewModel
A ProductViewModel also contains an observableArray - of ProductPriceViewModel
One feature I have is that I can duplicate a ProductViewModel and insert it into the ProductsViewModel array.
When I clone using:
ko.mapping.fromJS(ko.toJS(itemToCopy));
It doesn't appear to copy correctly - the prices observable array, isn't populated with ProductPriceViewModels - just Object
Here's the view models
var ProductsViewModel = function() {
var self = this;
self.products = ko.observableArray([new ProductViewModel()]);
self.addNewProduct = function() {
self.products.push(new ProductViewModel());
};
self.duplicateProduct = function() {
var itemToCopy = ko.utils.arrayFirst(self.products(), function(item) {
return item.visible();
});
//if i look at itemToCopy.prices() it is an array of ProductViewModel
var newItem = ko.mapping.fromJS(ko.toJS(itemToCopy));
//if i look at newItem.prices() it is an array of Object
self.products.push(newItem);
};
};
var ProductViewModel = function() {
var self = this;
self.name = ko.observable();
self.visible = ko.observable(true);
self.prices = ko.observableArray([new ProductPriceViewModel()]);
self.addPrice = function() {
self.prices.push(new ProductPriceViewModel());
};
};
var ProductPriceViewModel = function() {
var self = this;
self.name = ko.observable();
self.price = ko.observable();
};
I solved this by passing in a mapping configuration like this:
var mapping = {
'prices': {
create: function (options) {
return new ServicePriceViewModel(options.data);
}
}
};
on
var newItem = ko.mapping.fromJS(ko.toJS(productToCopy), mapping);
and changing my ProductPriceViewModel to accept data as a parameter:
var ProductPriceViewModel = function (data) {
var self = this;
self.name = ko.observable();
self.description = ko.observable();
self.price = ko.observable();
self.priceIsFrom = ko.observable();
if (data)
ko.mapping.fromJS(data, {}, this);
};
JSFiddle.
I am trying to push objects for an existing array into a knockout observable array but am failing terrible. How do I get this code to work, and since this code sucks what is the 'proper' way of doing this. Thank you so much
<div data-bind="foreach: Bob">
<div data-bind="text: $data">
</div>
</div>
var Test = function(){
var self= this;
self.Init = function(name){
self.Name = ko.observable(name);
};
};
var ArrayOfTests = function() {
var self = this;
self.Init = function(tests){
self.AllTests = ko.observableArray([]);
for(var i = 0; i <=tests.length-1;i++)
{
self.AllTests.push(tests[i]);
};
};
};
var TestViewModule = function(){
self.Bob = ko.observable();
var temp = new ArrayOfTests();
var tempTest = new Test();
tempTest.Init('one2');
temp.Init([tempTest,tempTest]);
self.Bob= temp;
};
ko.applyBindings(new TestViewModule());
console.log(new TestViewModule());
The answer ended up being, I was adding a null item to the array making the array not work.
You pass 'one2' string in Test.Init, but this method don't accept parameters:
var Test = function(){
var self= this;
self.Name = ko.observable();
self.Init = function(data){
self.Name(data);
};
};
Edit
I completly refactored your viewModel, because current implementation is not correct:
Html:
<div data-bind="with: Bob">
<div data-bind="foreach: AllTests">
<div data-bind="text: $data">
</div>
</div>
</div>
ViewModel:
var Test = function(){
var self= this;
self.Name = ko.observable(name);
self.Init = function(name){
self.Name(name);
};
};
var ArrayOfTests = function() {
var self = this;
self.AllTests = ko.observableArray();
self.Init = function(tests) {
for(var i = 0; i < tests.length; i++) {
self.AllTests.push(tests[i].Name());
};
};
};
var TestViewModule = function(){
var temp = new ArrayOfTests();
var tempTest = new Test();
tempTest.Init('one2');
temp.Init([tempTest,tempTest]);
self.Bob = ko.observable(temp);
};
ko.applyBindings(new TestViewModule());
console.log(new TestViewModule());
Can't map json to observable array. I use code from tutorial (http://learn.knockoutjs.com/).
function Movie(data) {
this.name = ko.observable(data.name);
this.description = ko.observable(data.description);
this.duration = ko.observable(data.duration);
this.id = ko.observable(data.id);
this.imdb_id = ko.observable(data.imdb_id);
this.original_name = ko.observable(data.original_name);
this.poster = ko.observable(data.poster);
this.type = ko.observable(data.type);
this.year = ko.observable(data.year);
}
function MovieListViewModel() {
// Data
var self = this;
self.moviesArray = ko.observableArray([]);
self.searchQuery = ko.observable();
self.searchMovies = function () {
$.getJSON("/api/v1/movies/search/", {"query": self.searchQuery }, function(allData) {
var mappedMovies = $.map(allData.movies, function(item) { return new Movie(item) });
console.log(mappedMovies); // in this line output: [Movie, Movie, Movie, Movie, Movie, Movie]
self.moviesArray(mappedMovies);
console.log(self.moviesArray); // in this line output: []
});
};
}
ko.applyBindings(new MovieListViewModel());
I do not understand what is wrong.
P.S. Sorry for my english
This
{"query": self.searchQuery }
Should be
{"query": self.searchQuery() }
This
console.log(self.moviesArray)
Should be
console.log(self.moviesArray())
How can I define a function in angular service, and then use the function definition in a function in another service.
I implement as below but it doesn't work. I don't want to return a ParentService instance, just a defintion of its constructor to be used as parent class of PersonService.
Thanks for your help.
var personModule = angular.module('personModule',['coreModule']).service('personService', function($q, jAjax){
function PersonService($q, jAjax) {
var self = this;
ParentService.call(self, $q, jAjax);
this.name = "person";
};
inherit(ParentService, PersonService);
PersonService.prototype.loadPersonList = function() {
var self = this;
var deferred = self.$q.defer();
ParentService.prototype.loadList.call(self, "meta", function(data){
self.items = data;
deferred.resolve(data);
});
return deferred.promise;
};
return new PersonService($q);
});
var coreModule = angular.module('coreModule',[]).service('commonService', function(jAjax){
var ParentService = function(jAjax) {
};
ParentService.prototype.loadList = function(docType, fn) {
var self = this;
var url = self.name + "/get";
self.jAjax.get(url).success(function(data) {
if (fn !== undefined) {
fn.call(this, data);
}
});
};
return ParentService;
});
Thanks for your time. I found the solution for this. In parentService, I return an object that contains the function definition
return {ParentService:ParentService};
, then in other module I get it as an property
inherit(commonService.ParentService, PersonService);
The fixed code is below
var personModule = angular.module('personModule',['coreModule']).service('personService', function($q, jAjax, commonService){
function PersonService($q, jAjax, commonService) {
var self = this;
ParentService.call(self, $q, jAjax);
this.name = "person";
};
inherit(commonService.ParentService, PersonService);
PersonService.prototype.loadPersonList = function() {
var self = this;
var deferred = self.$q.defer();
commonService.ParentService.prototype.loadList.call(self, "meta", function(data){
self.items = data;
deferred.resolve(data);
});
return deferred.promise;
};
return new PersonService($q, jAjax, commonService);
});
//Calling module
var coreModule = angular.module('coreModule',[]).service('commonService',function(jAjax){
var ParentService = function(jAjax) {
};
ParentService.prototype.loadList = function(docType, fn) {
var self = this;
var url = self.name + "/get";
self.jAjax.get(url).success(function(data) {
if (fn !== undefined) {
fn.call(this, data);
}
});
};
return {ParentService:ParentService};
});