I have a simple ng-click, which at present, is passing a $index value from an ng-repeat via ng-init.
What i would like to know is how can i pass another defined value into my ng-click?
Current HTML:
<div ng-repeat="values in Categories" id="history-{{$index}}" ng-init="sectionIndex = $index">
{{ values.Name }}, {{ values.Amount }}
</div>
<div>
<div class="left" ng-click="scrollLeft(sectionIndex)"></div>
<div class="right" ng-click="scrollRight(sectionIndex)"></div>
</div>
JS:
$scope.scrollLeft = scrollLeftRight.moveLeft;
$scope.scrollRight = scrollLeftRight.moveRight;
app.factory('scrollLeftRight', function () {
return {
moveLeft: function (sectionIndex) {
var scrollViewport_width = $(window).width();
var pixelsToMove = 0;
$('#history-' + sectionIndex).scrollLeft(pixelsToMove - 100);
pixelsToMove = pixelsToMove - 100;
if (pixelsToMove <= 0) {
pixelsToMove = 0; // reset
} else {
pixelsToMove = pixelsToMove;
}
},
moveRight: function (sectionIndex) {
var scrollViewport_width = $(window).width();
var pixelsToMove = 0;
$('#history-' + sectionIndex).scrollLeft(pixelsToMove + 100);
pixelsToMove = pixelsToMove + 100;
if (pixelsToMove >= scrollViewport_width) {
pixelsToMove = scrollViewport_width;
} else {
pixelsToMove = pixelsToMove;
}
}
};
});
What i would like to know, is how can i pass another value in my ng-init (if possible), so something like:
<div ng-repeat="values in Categories" id="history-{{$index}}" ng-init="sectionIndex = $index, tableID='history'">
So that my second parameter tableID, can be passed into my function:
moveRight: function (sectionIndex, tableID) {
And so that i no longer have to directly outline my id via:
$('#history-' + sectionIndex).scrollLeft(pixelsToMove - 100);
But instead:
$(tableID + sectionIndex).scrollLeft(pixelsToMove - 100);
There are Some ways to do this : I know 2 of them :p
1- Dummy way you can add A data-yourVariable into your Tag like this :
<div ng-repeat="values in Categories" id="history-{{$index}}" ng-init="sectionIndex = $index" data-table="history">
And in your ng-click you can do like this :
ng-click(sectionIndex,this.parent().data('table'));
2- Simple way : you can pass an object in your ng-init like this :
ng-init="{sectionIndex: $index, tableID:'history}"
NOTE: You must use(:) instead of (=) in your ng-init because you want to use it as an object
So in your ng-click :
ng-click(sectionIndex,tableID);
Hope that helps
Related
I created a function that creates a HTML chunk of code. Its ids are created dynamically with a tag variable collected from a form. Code:
$(function() {
$("#addTag").click(function() {
var tag = $("#tag").val();
$('section').append('<div id="galleryContainer' + tag + '"><div class=".gallery-header"><h1 >Tag:' + tag + '</h1><div class=".gallery-sort"><p>Sort by:</p><button onclick="sortImagesByPublishedDate()" >Data published</button><button onclick="sortImagesByTakenDate()">Data taken</button><div data-tag="' + tag + '" class="gallery component" id="' + tag + '"></div></div></div></div>');
mainFunction(tag);
});
});
Then I want to use sortImagesByPublishedDate() and sortImagesByTakenDate() by clicking a button, but I want them to sort images only in this particular gallery and not in all galleries. If I have one gallery, it works fine. Problems begin when I add more galleries. How should I select the variable $gallery in the following functions?
function sortImagesByPublishedDate() {
var $gallery = $('div.gallery'),
$galleryA = $gallery.children('a');
$galleryA.sort(function(a, b) {
var an = a.getAttribute('data-published'),
bn = b.getAttribute('data-published');
if (an > bn) {
return 1;
}
if (an < bn) {
return -1;
}
return 0;
});
$galleryA.detach().appendTo($gallery);
}
Use the .siblings method to select elements that are siblings of another element. So in your case you can just call
var $gallery = $(buttonElement).siblings(".gallery");
Since you are using inline JS to call the sort functions you need to modify it to pass this to your functions that way you can get a reference to the button that was clicked, ie:
Modified html
<button onclick="sortImagesByPublishedDate(this)">Date published</button>
JS
function sortImagesByPublishedDate(ele){
var $gallery = $(ele).siblings(".gallery"),
Demo
$(function(){
$("#addTag").click(function(){
var tag=$("#tag").val();
$('section').append('<div id="galleryContainer'+tag+'"><div class=".gallery-header"><h1 >Tag:'+tag+'</h1><div class=".gallery-sort"><p>Sort by:</p><button onclick="sortImagesByPublishedDate(this)" >Data published</button><button onclick="sortImagesByTakenDate(this)">Data taken</button><div data-tag="'+tag+'" class="gallery component" id="'+tag+'"></div></div></div></div>');
//mainFunction(tag);
});
});
function sortImagesByPublishedDate(ele){
var $gallery = $(ele).siblings(".gallery"),
$galleryA = $gallery.children('a');
alert($gallery[0].id);
$galleryA.sort(function(a,b){
var an = a.getAttribute('data-published'),
bn = b.getAttribute('data-published');
if(an > bn) {
return 1;
}
if(an < bn) {
return -1;
}
return 0;
});
$galleryA.detach().appendTo($gallery);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="tag">
<button id="addTag">Add</button>
<section>
</section>
Instead of inline js you could use delegated event handling to have listeners setup for your buttons:
Modified html
<button class="sortButton" data-sort="date">Data published</button>
<button class="sortButton" data-sort="taken">Data taken</button>
JS
$("section").on("click",".sortButton",function(){
//'this' will be the button clicked
var $gallery = $(this).siblings(".gallery");
var sortBy = $(this).data("sort");
if(sortBy == "date"){
//do date sort
} else if(sortBy == "taken"){
//do taken sort
}
//... rest of code
});
$(function() {
$("#addTag").click(function() {
var tag = $("#tag").val();
$('section').append('<div id="galleryContainer' + tag + '"><div class=".gallery-header"><h1 >Tag:' + tag + '</h1><div class=".gallery-sort"><p>Sort by:</p><button onclick="sortImagesByPublishedDate()" >Data published</button><button onclick="sortImagesByTakenDate()">Data taken</button><div data-tag="' + tag + '" class="gallery component" id="' + tag + '"></div></div></div></div>');
sortImagesByPublishedDate(tag); **// call the function and pass param tag**
mainFunction(tag);
});
});
function sortImagesByPublishedDate(tag) {
**// instead of class select id**
var $gallery = $('div#galleryContainer'+tag),
$galleryA = $gallery.children('a');
$galleryA.sort(function(a, b) {
var an = a.getAttribute('data-published'),
bn = b.getAttribute('data-published');
if (an > bn) {
return 1;
}
if (an < bn) {
return -1;
}
return 0;
});
$galleryA.detach().appendTo($gallery);
}
// hope this helps
Not tested but I think this will worl:
HTML:
sortImagesByPublishedDate(this)//pass this
JS:
function sortImagesByPublishedDate() {
var $gallery = $(this).siblings('.gallery'),
$galleryA = $gallery.children('a');
.
.
Pass this to sortImagesByPublishedDate(this) in your html of append
so your code is
function sortImagesByPublishedDate(thisObj) {
and then do
var $gallery = $(thisObj).siblings(".gallery");
Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>
I'm having a logic error with my code using angular js. What I have done is made a function that loops through a json array and returns the strings of the weather condition, eg
'clear',
'cloudy', etc...
It then checks to see if the value of the string is equal to another string. If it is, it returns an image link associated with the weather condition. The problem is that html ng-repeat function is repeating that one image and not any other image.
Here is the js:
var app=angular.module('app');
app.controller('MainCtrl', function($scope, $http) {
$scope.currentSydney = null;
$scope.currentMelbourne = null;
$scope.currentAdelaide = null;
$scope.currentDarwin = null;
$scope.currentBrisbane = null;
$scope.currentMelbourne = null;
$scope.currentCairns = null;
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Melbourne.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentMelbourne=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Sydney.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentSydney=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Adelaide.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentAdelaide=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Darwin.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentDarwin=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Perth.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentPerth=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Cairns.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentCairns=data;
});
$http.jsonp('http://api.wunderground.com/api/5ad0204df4bdbeff/conditions/q/Australia/Brisbane.json?callback=JSON_CALLBACK').success(function(data){
$scope.currentBrisbane=data;
$scope.cityData=[
{ name:'Brisbane',
temp:$scope.currentBrisbane.current_observation.temp_c,
image:$scope.currentBrisbane.current_observation.icon
},
{ name:'Melbourne',
temp:$scope.currentMelbourne.current_observation.temp_c,
image:$scope.currentMelbourne.current_observation.icon
},
{
name:'Adelaide',
temp:$scope.currentAdelaide.current_observation.temp_c ,
image:$scope.currentAdelaide.current_observation.icon
},
{ name:'Darwin',
temp:$scope.currentDarwin.current_observation.temp_c ,
image:$scope.currentDarwin.current_observation.icon
},
{ name:'Perth',
temp:$scope.currentPerth.current_observation.temp_c ,
image:$scope.currentPerth.current_observation.icon
},
{ name:'Cairns',
temp:$scope.currentCairns.current_observation.temp_c,
image:$scope.currentCairns.current_observation.icon
},
]
for(y = 0 ; y < 6; y++){
var string = $scope.cityData[y].image;
console.log(string[10]);
}
});
$scope.iconString = function() {
switch ($scope.currentSydney.current_observation.icon) {
case 'partlycloudy' :
return 'pics/partlycloudy.png';
case 'clear' :
return 'pics/partlycloudy.png';
}
}
$scope.repeat = function() {
for(y = 0 ; y < 1; y++){
var string = $scope.cityData[y].image;
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
}
});
And here is the html:
<div id="weather-container">
<div id="current-weather">
<!--Angular JSON pull -->
<div id="title"><span id="current-title">Current Weather</span></div>
<div id="current-condition">{{currentSydney.current_observation.weather}}</div>
<img ng-src="{{iconString()}}"></img>
<div id="current-temp"><span id="current-temp"> {{currentSydney.current_observation.temp_c}} </span></div>
<span id="current-city">{{currentSydney.current_observation.display_location.city}} </span>
</div>
<!--Angular JSON pull and iteration-->
<div id="other-city-container">
<div class="other-city-weather" ng-repeat="city in cityData" >
<!--Image-->
<img ng-src="{{repeat()}}"></img>
<div class="current-city-temp">
<span>{{city.temp}}</span>
</div>
<div class="current-city-lower">
<span>{{city.name}}</span>
</div>
</div>
</div>
</div>
Now I'm calling the repeat function in the html inside the img src tag.
`
I see. You are making 2 loops : ng-repeat in the view, and a for loop in the controller ( repeat() ).
But I think that right now, they are not related to each other (which is what you need I guess): getting the index of the ng-repeat loop in your repeat method.
Try something like that :
In the view :
<img ng-src="{{repeat($index)}}" /><!-- Getting the current $index of the ng-repeat loop and passing it to the $scope.repeat() method -->
In the controller :
$scope.repeat = function(index) { // there, index becomes the value we just put in the view ($index = the current index of the ng-repeat loop), e.g. : 0,1,2,3...
var string = $scope.cityData[index].image; // We go get the right city in the cityData array, according to the current ng-repeat index.
// then we do the job
if(string=='mostlycloudy'){
return 'pics/mostlycloudy.png';
}
}
Not sure that works as I didn't test it, but you may know what I mean ?
I'm learning the AngularJs and I've created a dynamic list with ng-repeat, but now I cannot find the solution for the next step...
I have the following code:
HTML:
<div ng-app="app">
<div class="list" ng-controller="ListController">
<div class="row" ng-repeat="prod in prodList">
<div class="prod-name cell">
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.id }}" data-cb="" /><label for="prod-{{ prod.id }}">{{ prod.name }}</label>
</div>
<div class="prod-size cell">
<label for="prodColor-#{{ prod.id }}">
<select id="prodColor-{{ prod.id }}" data-ng-model="orders.prods.color[prod.id]" data-ng-options="color.id as color.name for color in prod.colors">
<option value="">Select one</option>
</select>
</label>
</div>
<div class="prod-price cell">
{{ prod.price }}
</div>
</div>
<div class="sum">
{{ sum }}
</div>
</div>
</div>
JS:
var app = angular.module("app", [], function () {
});
app.controller('ListController', function ($scope) {
init();
function init () {
$scope.prodList = [{"id":"1","name":"window","colors":[{"id":"9","name":"white"},{"id":"11","name":"black"}],"price":"100"},{"id":"2","name":"door","colors":[{"id":"22","name":"blue"},{"id":"23","name":"red"}],"price":"356"},{"id":"3","name":"table","colors":[{"id":"37","name":"white"},{"id":"51","name":"black"}],"price":"505"}];
$scope.orders = {};
$scope.orders.prods = {};
$scope.orders.prods.prod = {};
$scope.orders.prods.color = {};
$scope.sum = 0;
}
});
Working demo:
http://jsfiddle.net/HDrzR/
Question
How can I calculate the summary of selected product's price into the $scope.sum?
Edited:
So if you select the "window" and the "table" from the list, the sum should contains 606. But if you unselect the "table" then the sum should be 100.
Thank you in advance!
You could either $watch over $scope.orders.prod and re-calculate the sum or (if performance is not a major concern and the list of objects is not huge) you could use a sum() function and reference it in the view:
Total: {{sum()}}
$scope.sum = function () {
return $scope.prodList.filter(function (prod) {
return $scope.orders.prods.prod[prod.id];
}).reduce(function (subtotal, selectedProd) {
return subtotal + parseInt(selectedProd.price);
}, 0);
};
/* If the above looks complicated, it is the equivalent of: */
$scope.sum = function () {
var sum = 0;
for (var i = 0; i < $scope.prodList.length, i++) {
var prod = $scope.prodList[i];
if ($scope.orders.prods.prod[prod.id]) {
sum += parseInt(prod.price);
}
}
return sum;
}
If you decide to go down the watching path, this is how the code should look like:
Total: {{watchedSum}}
$scope.sum = ...; // same as above
$scope.$watchCollection('orders.prods.prod', function (newValue, oldValue) {
if (newValue !== undefined) {
$scope.watchedSum = $scope.sum();
}
});
UPDATE:
"Stole" Quad's $watchCollection as this is more "cheap" than $watch(..., true).
As long as $scope.order.prods.prod contains only rimitive values (i.e. no objects), $watchCollection is enough to detect the changes.
See, also, this short demo illustrating both approaches.
here is an updated fiddle.
http://jsfiddle.net/HRQ9u/
what I did is add a $scope.$watch on the orders:
$scope.$watch('orders', function (newValue, oldValue) {
var findProdById = function (products, id) {
for (var i = 0; i < products.length; i++) {
if (parseInt(products[i].id, 10) === parseInt(id, 10)) {
return products[i];
}
}
return null;
};
var orders = newValue;
var usedProducts = newValue.prods.prod;
var sum = 0;
for ( var prop in usedProducts ){
var prodList = $scope.prodList;
var id = prop;
if ( usedProducts[id] ){
var product = findProdById(prodList, id);
if ( product !== null ){
sum += parseInt(product.price, 10);
}
}
}
$scope.sum = sum;
}, true);
Edit:
With that said, you can probably simplify your model a lot. And I mean A LOT.
Also, I have used only regular js as opposed to lodash or underscore.
Register an ng-click with checkbox and pass $event & prod.id references to a custom function that will be called on checkbox click event.
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" value="{{ prod.price }}" ng-click="calcSum($event, prod.id)" data-cb="" />
Within controller define custom function as:
$scope.calcSum = function($event, id) {
var checkbox = $event.target;
if (checkbox.checked ) {
$scope.sum += parseInt(checkbox.value);
} else {
$scope.sum -= parseInt(checkbox.value);
}
}
Change the Checkbox value attribute to store {{ prod.price }} instead of {{ prod.id }}, it makes more sense.
From my POV it looks more appropriate to use is ngChange from the input[checkbox] itself. Like:
ng-change="addMe(prod.price);"
We need a way to differentiate checked from not checked and in order to change less your app we will use the existence of the object by it doing this way:
ng-change="addMe(orders.prods.prod[prod.id],prod.price);"
ng-true-value="{{ prod.id }}"
ng-false-value=""
The full HTML will look like this:
<input type="checkbox" id="prod-{{ prod.id }}" data-ng-model="orders.prods.prod[prod.id]" ng-change="addMe(orders.prods.prod[prod.id],prod.price);" ng-true-value="{{ prod.id }}" ng-false-value="" />
From your Controller all you need is to add or substract when necessary:
$scope.addMe=function(checked,val){
val = 1*val
if (!checked){ $scope.sum = $scope.sum-val;}
else { $scope.sum = $scope.sum +val; }
}
Here is the Online Demo
Updated your fiddle FIDDLE
You can $scope.$watchCollection your scope to calcuate new sum. I chaged your prodList prices to number instead of string, and used underscore.js for easier looping in your objects/arrays.
$scope.$watchCollection("orders.prods.prod",function(){
var sum = 0;
for(var i = 0;i<$scope.prodList.length;i++){
if($scope.orders.prods.prod[$scope.prodList[i].id]){
sum += $scope.prodList[i].price;
}
}
$scope.sum = sum;
});
watchCollection docs are here
edit: changed with regular js answer
I have an array that I'm removing items from but I'm keeping count of the number of items to do UI formatting. I need to be able to have the bind update.
ko.applyBindings(viewModel);
getFoos();
var viewModel = {
foos: ko.observableArray([]),
reloadFoos: function () {
getFoos();
},
removeFoo: function () {
remove(this);
}
};
var foo = function () {
this.Id = ko.observable();
this.Name = ko.observable();
this.Count = ko.observable();
};
function remove(foo) {
viewModel.foos.splice(viewModel.foos.indexOf(foo), 1);
viewModel.foos.each(function(index) {
viewModel.foos[index].Count = index%10 == 0;
});
}
function getFoos() {
viewModel.foos([]);
$.get("/myroute/", "", function (data) {
for (var i = 0; i < data.length; i++) {
var f = new foo();
f.Id = data[i];
f.Name = data[i];
f.Count = i%10 == 0;
viewModel.foos.push(f);
}
});
}
<div data-bind="foreach: foos">
<div style="float: left">
<a href="javascript:void(0);" data-bind="click : $parent.removeFoo, attr: { id: Id }">
<label data-bind="value: Name"></label>
</a>
</div>
<!-- ko if: Count -->
<div style="clear: left"></div>
<!-- /ko -->
</div>
When the click event fires the item is removed from the array but the if bind doesn't get updated and the ui formatting is off. I'm trying to keep from reloading the data because the ui block bounces as it removes and reloads.
Your UI is not being updated because when you do your assignment to Count, you aren't assigning as an observable. You are replacing the observable with a straight boolean value. So, your assignment calls like this one:
viewModel.foos[index].Count = index%10 == 0;
Will cause viewModel.foos[index].Count to be equal to true or false and the value won't be stored in the observable.
That line should be this instead:
viewModel.foos[index].Count(index%10 == 0);
That will set the observable correctly. Note that you must change all of your assignments to observables to be set this way. See the "Reading and Writing Observables" section of this page: Knockout Observables.