The view has a heading followed by section with has submenus. the design for the viewmodels is below:
SettingsViewModel = function (pName) {
var self = this;
self.productName = ko.observable(pName), //heading
self.sections = ko.observableArray([
{ checkboxID: ko.observable(), checkboxIDState: ko.observable(), sectionname: ko.observable(), sectionState: ko.observable() }
]), //submenus
self.Addsections = function (checkboxid, sIdState, sName, sState) {
this.sections.push({ checkboxID: checkboxid, checkboxIDState: sIdState, sectionname: sName, sectionState: sState });
}
};
function MainViewModel() {
var self = this;
self.products = ko.observableArray([]);
self.AddProducts= function (pname) {
self.products.push(new SettingsViewModel(pname));
}
};
$(document).ready(function () {
VM = new MainViewModel();
ko.applyBindings(VM, document.getElementById("divd"));
data= []; //some dummy data
CallMEnus(data);
});
function CallMEnus(data) {
var str = "";
$(data).each(function (index, products) {
VM.AddProducts(products.name);
$(products.section).each(function (index, section) {
var ChkboxId = "data";
var chkboxIdState = 'datt';
var chkboxIdState += " checked";
}
//how to call the products add section method?
VM.products()[index].Addsections(ChkboxId, chkboxIdState, section.name, section.state);
});
});
I need to call the AddSections method of the nested SettingsViewModel from MainViewModel instance. How to achieve this?
Thanks in advance.
Your problem is that parameter index from sections loop hides index from products loop. Just use another parameter name:
function CallMEnus(data) {
var str = "";
$(data).each(function (index, products) {
VM.AddProducts(products.name);
$(products.section).each(function(i, section) { // here
var id = "data";
var state = "checked";
VM.products()[index].Addsections(id, state, section.name, section.state);
});
});
};
Fiddle
I would use a EventAggregator to decouple viewmodels, I've written this lightweight EventAggregator
http://jsfiddle.net/wJtun/4/
Subscribe:
MyApp.eventAggregator.subscribe(MyApp.DeleteCustomerMessage, this.customerDeleted, this);
Publish:
MyApp.eventAggregator.publish(new MyApp.DeleteCustomerMessage(this));
Related
I have two observable arrays:
var viewModel = {
PositionTypes: ko.observableArray([]),
Users: ko.observableArray([])
}
POSITION ViewModel
var positionViewModel = function (data) {
var _self = this;
_self.PositionName = ko.observable(data.PositionName);
_self.PositionRank = ko.observable(data.PositionRank);
_self.ContentRole = ko.observable(data.ContentRole);
}
positionViewModel.AddPositions = function (data) {
$.each(data, function (index, value) {
positionViewModel.PushPosition(value);
});
};
positionViewModel.PushPosition = function (postion) {
viewModel.PositionTypes.push(new positionViewModel(position));
};
USER ViewModel
// the ViewModel for a single User
var userViewModel = function (data) {
var _self = this;
_self.ID = ko.observable(data.ID);
_self.Name = ko.observable(data.Name);
_self.Email = ko.observable(data.Email);
_self.ContentRole = ko.observable(data.ContentRole);
};
userViewModel.AddUsers = function (data) {
$.each(data, function (index, value) {
userViewModel.PushUser(value);
});
};
userViewModel.PushUser = function (user) {
viewModel.Users.push(new userViewModel(user));
};
How can i using linq.js so that i could loop through every position so i could get all the users for each position?
foreach( each position in positions)
{
foreach(each user in users)
{ list of users for the position}
}
You could also use ko.utils.arrayForEach as follow :
ko.utils.arrayForEach(viewModel.PositionTypes(), function(position){
var usersInPosition = ko.utils.arrayFilter(viewModel.Users(), function(user){
return user.ContentRole() == position.ContentRole();
});
ko.utils.arrayForEach(usersInPosition, function(user){
});
});
See doc
I hope it helps.
Using linq.js, you can perform a join on the columns you want to compare.
Assuming you are joining between the ContentRoles:
var query = Enumerable.From(viewModel.PositionTypes())
.GroupJoin(viewModel.Users(),
"$.ContentRole()", // position selector
"$.ContentRole()", // user selector
"{ Position: $, Users: $$.ToArray() }")
.ToArray();
So I think you want to create an object that contains a mapping of all the positions and user names. You can create such an object using the Aggregate() function to collect all the results into a single object.
var userPositions = Enumerable.From(this.PositionTypes())
.GroupJoin(this.Users(),
"$.ContentRole()", // position selector
"$.ContentRole()", // user selector
"{ Position: $, Users: $$ }") // group all users per position
.Aggregate(
{}, // start with an empty object
function (userPositions, x) {
var positionName = x.Position.PositionName(),
userNames = x.Users.Select("$.Name()").ToArray();
// add the new property
userPositions[positionName] = userNames;
return userPositions;
}
);
I have two collections of objects. I iterate trough collection A and I want when ObjectId from A matches ObjectId from B, to update that Object in collection B.
Here is what I got so far:
var exerciseIds = _(queryItems).pluck('ExerciseId').uniq().valueOf();
var item = { Exercise: null, ExerciseCategories: [] };
var exerciseAndCategories = [];
//this part works fine
_.forEach(exerciseIds, function(id) {
var temp = _.findWhere(queryItems, { 'ExerciseId': id });
item.Exercise = temp.Exercise;
exerciseAndCategories.push(item);
});
//this is problem
_.forEach(queryItems, function (i) {
_(exerciseAndCategories).where({ 'ExerciseId': i.ExerciseId }).tap(function (x) {
x.ExerciseCategories.push(i.ExerciseCategory);
}).valueOf();
});
EDIT
Link to a Fiddle
Give this a try:
var exerciseIds = _(queryItems).pluck('ExerciseId').uniq().valueOf();
var item = {
Exercise: null,
ExerciseCategories: []
};
var exerciseAndCategories = [];
//this part works fine
_.forEach(exerciseIds, function (id) {
var temp = _.findWhere(queryItems, {
'ExerciseId': id
});
var newItem = _.clone(item);
newItem.Exercise = temp.ExerciseId;
exerciseAndCategories.push(newItem);
});
//this is problem
_.forEach(queryItems, function (i) {
_(exerciseAndCategories).where({
'Exercise': i.ExerciseId
}).tap(function (x) {
return _.forEach(x, function(item) {
item.ExerciseCategories.push(i.ExerciseCategory);
});
}).valueOf();
});
// exerciseAndCategories = [{"Exercise":1,"ExerciseCategories":["biking","cardio"]},{"Exercise":2,"ExerciseCategories":["biking","cardio"]}]
Main problem was that tap returns the array, not each item, so you have to use _.forEach within that.
FIDDLE
contactManager.controller('contactsList',
function contactsList($scope){
$scope.myId = 0;
$scope.contacts = [{id:$scope.myId,name:'Default',mail:'test#cognizant.com',mobile:'000000'},
{id:$scope.myId++,name:'andefined',mail:'undefined#cognizant.com',mobile:'1111'}];
});
contactManager.controller('addContactCtrl',
function addContactCtrl($scope,$location){
$scope.contact = {};
$scope.add = function(){
if($scope.contact.name){
$scope.contact.id = $scope.myId++; // **Increment Doesn't happen Here. It assigns the same value evertime**
$scope.contacts.push($scope.contact);
$location.url('/');
}
else{
alert('Name is mandatory');
}
};
});
Increment doesn't happen in $scope.myId++ !
I'm trying the assign id's to every new contact added to the list, but the id's are not getting incremented !!
You are better off using a service that provides the ID for you. You can create a service as follows:
contactManager.service('uniqueIds', function () {
var currentId = null;
return {
getNextId: function () {
if (currentId === null) {
currentId = 0;
} else {
currentId = currentId + 1;
}
return currentId;
}
}:
});
You can then use this service in your controllers as follows:
contactManager.controller('contactsList', ['$scope', 'uniqueIds', function ($scope, uniqueIds) {
$scope.contacts = {
id: uniqueIds.getNextId(), //Service call
name: 'Default',
mail: 'test#abc.com',
mobile:'000000'
}, {
id: uniqueIds.getNextId(), //Service call
name: 'undefined',
mail: 'undefined#xyz.com',
mobile:'1111'
}];
});
contactManager.controller('addContactCtrl', ['$scope', '$location', 'uniqueIds', function ($scope, $location, uniqueIds) {
$scope.contact = {};
$scope.add = function(){
if($scope.contact.name){
$scope.contact.id = uniqueIds.getNextId(); //Service call
$scope.contacts.push($scope.contact);
$location.url('/');
} else {
alert('Name is mandatory');
}
};
});
EDIT: If you are looking to generate uniqueIds, then this is not the way to go - You may want to check this out to generate them.
I'm new to Knockoutjs. I have a very simple model with name, value and history variables. I've tried several approaches but can not get the history to update more then 1 iteration. Most approaches failed with scope access issues. As I said I'm new to knockeout. I've also included this Fiddle that illustrates the issues well.
this.tlmname = ko.observable();
this.tlmval = ko.observable();
this.history = ko.observableArray();
var telemItem = function (data) {
this.tlmname = ko.observable();
this.tlmval = ko.observable();
this.history = ko.observableArray();
this.update(data);
};
ko.utils.extend(telemItem.prototype, {
update: function(data) {
this.tlmname(data.tlmname|| "Cheese");
this.tlmval(data.tlmval || 0);
this.history.push(data.tlmval);
if (this.history().length > 50) this.history.shift();
}
});
var telemetryViewModel = function(telemVars) {
this.telemVars = ko.observableArray(ko.utils.arrayMap(telemVars, function(data) {
return new telemItem(data);
}));
function UpdateModel( modelView ) {
$.getJSON('/gtr/tests/ko/requestTelemetry.php',
function(data)
{
//modelView.telemVars(data.telemVars);
//modelView(data.telemVars);
modelView.update(data.telemVars);
modelView.telemVarsDirect( getDirectVM( data.telemVars ) );
}
)};
I have this structure:
MyApp.User = function()
{
var self = this;
self.ID = ko.obervable();
self.Name = ko.obervable();
self.LastName = ko.observable();
}
MyApp.UserHub = function()
{
self.users = ko.observableArray();
$.getJSON("url", function (data) {
var mappedUser = $.map(data.UsersFromJson, function (item) {
return new MyApp.User(item);
});
self.users(mappedUsers);
});
}
I have a observableArray, which I populated using a HTML Request and a JSON (That works just fine). The thing is that I want to be able to search in that observableArray a user, providing information that can be contained in the LastName or in the FirstName. Something like this:
self.searchedUsers = ko.observableArray();
for(var item in users)
{
if(item.FirstName.Contains(query) || item.LastName.Contains(query))
{
self.searchedUser.push(item);
}
}
Query is the input text value that I want to search. Can anyone help to iterate that ObservableArray?
Generally, you would want to create a computed observable to represent a filtered version of your array.
So, you would have something like:
self.users = ko.observableArray();
self.query = ko.observable();
self.filteredUsers = ko.computed(function() {
var query = self.query();
return ko.utils.arrayFilter(self.users(), function(user) {
return user.FirstName.indexOf(query) > -1 || user.LastName.indexOf(query) > -1;
});
});
I also hink you have to iterate over self.users() instead of users.
users is the observableArray-function while users() provides access to the underlying data.