Observable Array and foreach Lists - javascript

I have this code:
<select multiple="multiple" data-bind="options:markerResults, optionsText: function(item) {
return item.name +' '+ item.formatted_address
}">
</select>
And it works. But, This code:
<ul data-bind="foreach: markerResults">
<li>
<stong><span data-bind:"text: name"></span></strong>
<span data-bind:"text: formatted_address"></span>
<span data-bind:"text: rating"></span>
</li>
</ul>
Doesn't. How can I make the code above work?
Thank you!
more code:
for (var j = 0; j < allResults.length; j++) {
createMarker(allResults[j]);
allResults.push(results);
console.log(allResults);
}
}

here is the fiddle http://jsfiddle.net/LkqTU/32252/
function model() {
var self = this;
this.text = ko.observable('hello');
this.markerResults = ko.observableArray([
{ name: "Bungle", formatted_address: "1 My Way", rating: 'A' },
{ name: "George", formatted_address: "2 My Way", rating: 'B' },
{ name: "Zippy", formatted_address: "3 My Way", rating: 'C' }
]);
}
var mymodel = new model();
$(document).ready(function() {
ko.applyBindings(mymodel);
});
here is the html
<ul data-bind="foreach: markerResults">
<li>
<strong><span data-bind="text: name"></span></strong>
<strong><span data-bind="text: formatted_address"></span></strong>
<strong><span data-bind="text: rating"></span></strong>
</li>
</ul>

Related

Filtering array based on selected checkboxes and select fields

How can I store the selected values of checkboxes and select elements and use a combination of these to filter a results array? e.g. think filtering by category Id, or displaying all results in the last X months.
After much research and trial and error I've got as far as this:
View Plunker or see the code below:
HTML within the 'refine' directive
<div class="filters">
<div class="filter">
<label for="maxage">Show results from</label>
<select name="maxage" id="maxage"
ng-options="option.name for option in refine.maxAge.options track by option.id"
ng-model="refine.maxAge.selected"
ng-change="filterResults()">
</select>
</div>
<div class="filter">
<div class="status-filter" ng-repeat="status in refine.statuses">
<label for="statusId{{ status.id }}">{{ status.name }}</label>
<input type="checkbox" name="status" value="{{ status.id }}" ng-change="filterResults()">
</div>
</div>
</div>
HTML of main page
<body ng-app="app">
<div ng-controller="ListCtrl" data-county-parish-id="1478">
...
<main class="page-content columns medium-9 medium-push-3">
...
<spinner name="planningSpinner" show="true">
<div class="loadingPanel block"></div>
</spinner>
<div class="planning">
<div class="no-results ng-hide" ng-show="filteredResults.length === 0">
<p>No results.</p>
</div>
<h4>Number of records: {{ filteredResults.length }}</h4>
<div ng-repeat="appl in filteredResults">
<hf-application info="appl"></hf-application>
</div>
</div>
...
</main>
<aside class="sidebar columns medium-3 medium-pull-9">
...
<div hf-refine-results info="refine"></div>
</aside>
...
</div>
</body>
JS
var app = angular.module('app', []);
// results filter
angular.module('app').filter('results', ['$filter', function($filter) {
return function (input, refine) {
var filterParams = {};
// start off filtering with the outsideBoundary parameter
filterParams.outsideBoundary = refine.outsideBoundary;
// add 'show results from' filter
//var adjustedDate = new Date();
//adjustedDate.setMonth(adjustedDate.getMonth() - refine.maxAge.selected.id);
//filterParams.receivedDate = $filter('date')(adjustedDate, 'yyyy/MM/dd');
return $filter('filter')(input, filterParams);
}
}]);
// Controller
angular.module('app').controller('ListCtrl',
['$scope', '$filter', '$attrs', 'appService', 'resultsFilter', function ($scope, $filter, $attrs, appService, resultsFilter) {
$scope.applications = [];
$scope.refine = {
statuses: {
options: [
{ id: 1, name: 'Unknown' },
...
{ id: 6, name: 'Appealed' }
],
selected: [2, 3]
},
maxAge: {
options: [
{ id: '1', name: 'Last month' },
... // 1 to 12 months
{ id: '12', name: 'Last 12 months' }
],
selected: { id: '6', name: 'Last 6 months' }
},
...
};
$scope.filterResults = function () {
$scope.filteredResults = resultsFilter($scope.applications, $scope.refine);
};
/* get data from appService */
appService.getApplications({
status: 3,
countyparish: parseInt($attrs.countyParishId),
postcode: '',
distance: 5,
pagesize: 100
})
.then(function (data) {
$scope.applications = data;
$scope.filteredResults = resultsFilter(data, $scope.refine);
});
}]);
I appreciate this question has been asked many times, however I haven't found an answer for my question(s) since most examples are very simple expressions within ng-repeat.
This example work with multi checkbox. For filtering with outher select use same logic. Look
'use strict';
var App = angular.module('clientApp', ['ngResource', 'App.filters']);
App.controller('ClientCtrl', ['$scope', function ($scope) {
$scope.selectedCompany = [];
$scope.companyList = [{
id: 1,
name: 'Apple'
}, {
id: 2,
name: 'Facebook'
}, {
id: 3,
name: 'Google'
}];
$scope.clients = [{
name: 'Brett',
designation: 'Software Engineer',
company: {
id: 1,
name: 'Apple'
}
}, {
name: 'Steven',
designation: 'Database Administrator',
company: {
id: 3,
name: 'Google'
}
}, {
name: 'Jim',
designation: 'Designer',
company: {
id: 2,
name: 'Facebook'
}
}, {
name: 'Michael',
designation: 'Front-End Developer',
company: {
id: 1,
name: 'Apple'
}
}, {
name: 'Josh',
designation: 'Network Engineer',
company: {
id: 3,
name: 'Google'
}
}, {
name: 'Ellie',
designation: 'Internet Marketing Engineer',
company: {
id: 1,
name: 'Apple'
}
}];
$scope.setSelectedClient = function () {
var id = this.company.id;
if (_.contains($scope.selectedCompany, id)) {
$scope.selectedCompany = _.without($scope.selectedCompany, id);
} else {
$scope.selectedCompany.push(id);
}
return false;
};
$scope.isChecked = function (id) {
if (_.contains($scope.selectedCompany, id)) {
return 'icon-ok pull-right';
}
return false;
};
$scope.checkAll = function () {
$scope.selectedCompany = _.pluck($scope.companyList, 'id');
};
}]);
angular.module('App.filters', []).filter('companyFilter', [function () {
return function (clients, selectedCompany) {
if (!angular.isUndefined(clients) && !angular.isUndefined(selectedCompany) && selectedCompany.length > 0) {
var tempClients = [];
angular.forEach(selectedCompany, function (id) {
angular.forEach(clients, function (client) {
if (angular.equals(client.company.id, id)) {
tempClients.push(client);
}
});
});
return tempClients;
} else {
return clients;
}
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular-resource.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css">
<div ng-app="clientApp" data-ng-controller="ClientCtrl">
<ul class="inline">
<li>
<div class="alert alert-info">
<h4>Total Filtered Client: {{filtered.length}}</h4>
</div>
</li>
<li>
<div class="btn-group" data-ng-class="{open: open}">
<button class="btn">Filter by Company</button>
<button class="btn dropdown-toggle" data-ng-click="open=!open"><span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu">
<li><a data-ng-click="checkAll()"><i class="icon-ok-sign"></i> Check All</a>
</li>
<li><a data-ng-click="selectedCompany=[];"><i class="icon-remove-sign"></i> Uncheck All</a>
</li>
<li class="divider"></li>
<li data-ng-repeat="company in companyList"> <a data-ng-click="setSelectedClient()">{{company.name}}<span data-ng-class="isChecked(company.id)"></span></a>
</li>
</ul>
</div>
</li>
</ul>
<hr/>
<h3>Clients Table:</h3>
<table class="table table-hover table-striped">
<thead>
<tr>
<th style="width:10%">#</th>
<th style="width:20%">Name</th>
<th style="width:40%">Designation</th>
<th style="width:30%">Company</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="client in filtered = (clients | companyFilter:selectedCompany)">
<td>{{$index + 1}}</td>
<td><em>{{client.name}}</em>
</td>
<td>{{client.designation}}</td>
<td>{{client.company.name}}</td>
</tr>
</tbody>
</table>
</div>

knockout - how to subscribe for multiple dropdown menus (select) and bind to a model

SO lovers and javascript developers,
How can I bind multiple dropdowns to a model and subscripe its' change events individually for each dropdown?
I have a basic form for that.. You can see it live in jsFiddle: http://jsfiddle.net/2Mnr3/7/
Why all select fields changes together when I select one? How can I do it in individually way?
Here it's my HTML:
<div class='liveExample'>
<h2>Orders</h2>
<div id='contactsList'>
<table class='contactsEditor'>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Service</th>
</tr>
<tbody data-bind="foreach: contacts">
<tr>
<td>
<input data-bind='value: firstName' />
<div><a href='#' data-bind='click: $root.removeContact'>Delete</a></div>
</td>
<td><input data-bind='value: lastName' /></td>
<td>
<table>
<tbody data-bind="foreach: services">
<tr>
<td>
<select data-bind='options: catalog, value: $root.selectedId, optionsText: "name", optionsCaption: "Select..."'> </select>
</td>
<td>
<div data-bind="visible: $root.selectedId()">
<span data-bind='text: $root.selectedId.price'> </span>
<!--<span data-bind='text: "asd"'> </span>-->
</div>
<td>
<a href='#' data-bind='click: $root.removeService'>Delete</a></td>
</tr>
</tbody>
</table>
<a href='#' data-bind='click: $root.addService'>Add service</a>
</td>
</tr>
</tbody>
</table>
</div>
<p>
<button data-bind='click: addContact'>Add customer </button>
<button data-bind='click: save, enable: contacts().length > 0'>JSON</button>
</p>
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled
='disabled'> </textarea>
And Javascript Code with Knockout library:
function formatCurrency(value) {
console.log(value);
return value;
}
var serviceTypes = [
{ name: "Service One", id: "1", price: "10 USD"},
{ name: "Service Two", id: "2", price: "9 USD"},
{ name: "Service Three", id: "3", price: "25 USD"},
{ name: "Service Four", id: "4", price: "42 USD"}
];
var initialData = [
{ firstName: "John", lastName: "Carter", services: [{ catalog: serviceTypes, id: 0 }, { catalog: serviceTypes, id: 2 }]
}
];
function ContactsModel(contacts) {
var self = this;
self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function(contact) {
return { id: contact.id, firstName: contact.firstName, lastName: contact.lastName, services: ko.observableArray(contact.services) };
}));
self.serviceTypes = ko.observableArray(serviceTypes);
self.selectedId = ko.observable('1');
self.selectedId.subscribe(function(item){
return ko.utils.arrayFirst(serviceTypes, function(service) {
return service;
});
});
self.addContact = function() {
self.contacts.push({
firstName: "",
lastName: "",
services: ko.observableArray([
{
catalog: this.serviceTypes,
}])
});
};
self.removeContact = function(contact) {
self.contacts.remove(contact);
};
self.addService = function(contact) {
contact.services.push({
catalog: self.serviceTypes,
});
};
self.removeService = function(phone) {
$.each(self.contacts(), function() { this.services.remove(phone) })
};
self.save = function() {
self.lastSavedJson(JSON.stringify(ko.toJS(self.contacts), null, 2));
};
self.lastSavedJson = ko.observable("")
};
ko.applyBindings(new ContactsModel(initialData));
You are sharing same observable($root.selectedId) instead of this every catalog should have there own copy of selectedId. for that you can use constructor function eg,
function Catalog(serviceTypes, d) {
this.catalog = serviceTypes;
this.selectedId = ko.observable(d || null);
this.selectedId.subscribe(function (item) {
//Subscriber Handler
});
}
var initialData = [{
firstName: "John",
lastName: "Carter",
services: [new Catalog(serviceTypes, 1), new Catalog(serviceTypes, 2)]
}];
addContact and addService function are also changed.
self.addContact = function () {
self.contacts.push({
firstName: "",
lastName: "",
services: ko.observableArray([new Catalog(serviceTypes)])
});
};
self.addService = function (contact) {
contact.services.push(new Catalog(serviceTypes));
};
Fiddle Demo
You are binding all your services select elements to the same $root.selectedId value.That's why the corresponding subscribe is being fired upon any change in any of them.
You need to bind the value dynamically based on the contact record for example.

Knockoutjs model does not update when select options change

I have a computed function which doesn't update the UI when a select options change. But works fine if I add or remove a line.
This is the HTML:
<button data-bind="click: add">Add New</button>
<ul data-bind="foreach: items">
<li>
<label data-bind="text: name"></label>
<select data-bind="options: [1,2,3], value: val"> </select>
</li>
</ul>
TOTAL: <span data-bind="text: total"></span>
And this the JavaScritp:
function viewModel (initialItems) {
this.items = ko.observableArray(initialItems);
this.total = ko.computed(function () {
var total = 0;
for (var i = 0; i < this.items().length; i++)
total += this.items()[i].val;
return total;
}, this);
this.add = function() { this.items.push({name: "New", val: 1}); };
}
ko.applyBindings(new viewModel([{name: "Alpha", val: 2},
{name: "Beta", val: 3},
{name: "Gamma", val: 1}]));
And here is the fiddle: http://jsfiddle.net/waUE4/
How can I get the model update when selection change?
Thanks for your help.
Edit
Working version: http://jsfiddle.net/fCE3a/1/
The reason why the val property is not updated is that it is not declared as an Observable property.
Check out this sample code from the official KnockoutJS website, it looks like what you want to do: Cart editor example

jQuery org chart how to sort the items?

I'am using this plugin: http://th3silverlining.com/2011/12/01/jquery-org-chart-a-plugin-for-visualising-data-in-a-tree-like-structure/
the question is how can I sort the <ul> items in the way I need it? are there some options or maybe some solutions out of the box?
Try this,
Demo
HTML
<div class="topbar">
<div class="topbar-inner">
<div class="container">
<a class="brand" href="#">jQuery Organisation Chart</a>
<ul class="nav">
<li>Github</li>
<li>Twitter</li>
<li>Blog</li>
</ul>
<div class="pull-right">
<div class="alert-message info" id="show-list">Show underlying list.</div>
<pre class="prettyprint lang-html" id="list-html" style="display:none"></pre>
</div>
</div>
</div>
</div>
<ul id="org" style="display:none">
<li>
Food
<ul>
<li id="beer">Beer</li>
<li>Vegetables
Click me
<ul>
<li>Pumpkin</li>
<li>
Aubergine
<p>A link and paragraph is all we need.</p>
</li>
</ul>
</li>
<li class="fruit">Fruit
<ul>
<li>Apple
<ul>
<li>Granny Smith</li>
</ul>
</li>
<li>Berries
<ul>
<li>Blueberry</li>
<li><img src="images/raspberry.jpg" alt="Raspberry"/></li>
<li>Cucumber</li>
</ul>
</li>
</ul>
</li>
<li>Bread</li>
<li class="collapsed">Chocolate
<ul>
<li>Topdeck</li>
<li>Reese's Cups</li>
</ul>
</li>
</ul>
</li>
</ul>
<div id="chart" class="orgChart"></div>
Jquery:
jQuery(document).ready(function() {
$("#org").jOrgChart({
chartElement : '#chart',
dragAndDrop : true
});
$("#show-list").click(function(e){
e.preventDefault();
$('#list-html').toggle('fast', function(){
if($(this).is(':visible')){
$('#show-list').text('Hide underlying list.');
$(".topbar").fadeTo('fast',0.9);
}else{
$('#show-list').text('Show underlying list.');
$(".topbar").fadeTo('fast',1);
}
});
});
$('#list-html').text($('#org').html());
$("#org").bind("DOMSubtreeModified", function() {
$('#list-html').text('');
$('#list-html').text($('#org').html());
prettyPrint();
});
});
////////////You can use this plugin also for json data
////////////Example
$(document).ready(function () {
var ds = [{ id: "2", parentid: "1", text: "India", children: [{ id: "5", parentid: "2", text: "MP", children: [{ id: "7", parentid: "5", text: "Indore", children: [{ id: "8", parentid: "7", text: "Tillore", children: [] }] }] }, { id: "6", parentid: "2", text: "UP", children: [] }] }, { id: "3", parentid: "1", text: "Rusia", children: [] }, { id: "4", parentid: "1", text: "China", children: [] }];
$("#mystring").CustomOrgChart({ dataSource: ds, hasTemplate: true, template: "<div style='color:red;' data-cardid='{0}'><span class='cardadd'>Add</span> <span class='cardedit'>edit</span> <span class='cardremove'>delete</span>{1}</div>",templatefields: ["id","text"] });
$("#custome").jOrgChart({
chartElement: '#string',
dragAndDrop: true
});
});
////////////Plugin
(function ($) {
jQuery.fn.CustomOrgChart = function (options) {
var defaults = {
dataSource: [],
dispalyText: "text",
children: "children",
hasTemplate: false,
template: "{0}",
templatefields: ["text"]
};
var settings = $.extend(true, {}, defaults, options);
if (settings.dataSource) {
var string = "<ul id='custome' style='display:none'>" + GetNodes(settings.dataSource) + "</ul>";
console.log(string);
(this).append(string);
return this;
}
function GetNodes(dataSource) {
var Node = "";
var dataSource = dataSource.slice(0);
var dataSourceArray = $.isArray(dataSource[0]) ? dataSource : [dataSource];
for (var i = 0; i < dataSourceArray.length; i++) {
for (var j = 0; j < dataSourceArray[i].length; j++) {
var text = dataSourceArray[i][j][settings.dispalyText];
var children = dataSourceArray[i][j][settings.children];
Node += "<li>";
var template = settings.template;
var templatefields = settings.templatefields;
if (settings.hasTemplate) {
for (var k = 0; k < templatefields.length; k++) {
template = template.replace("{" + k + "}", dataSourceArray[i][j][templatefields[k]]);
}
Node += template;
}
else {
for (var k = 0; k < templatefields.length; k++) {
template = template.replace("{" + k + "}", dataSourceArray[i][j][templatefields[k]]);
}
Node += template;
}
if (children.length > 0) {
Node += "<ul>" + GetNodes(children) + "</ul>";
}
Node += "</li>";
}
}
return Node;
}
};
})(jQuery);

Knockout "with" binding

I am trying to display descendant elements in array using "with" binding.
But it displays only last items in "exercises" and I want to see all of them. How is it possible to fix this?
And after that, how can I make each item in array editable?
My ViewModel:
function AppViewModel() {
var self = this;
self.workouts = ko.observableArray([
{name: "Workout1", exercises:{
name: "Exercise1.1",
name: "Exercise1.2",
name: "Exercise1.3"
}},
{name: "Workout2", exercises:{
name: "Exercise2.1",
name: "Exercise2.2",
name: "Exercise2.3"
}},
{name: "Workout3", exercises:{
name: "Exercise3.1",
name: "Exercise3.2",
name: "Exercise3.3"
}},
{name: "Workout4", exercises:{
name: "Exercise3.1",
name: "Exercise3.2",
name: "Exercise3.3"
}},
]);
self.removeWorkout = function() {
self.workouts.remove(this);
};
}
ko.applyBindings(new AppViewModel());
The View:
<div class="content">
<ul data-bind="foreach: workouts">
<li>
<span data-bind="text: name"> </span>
Remove
<ul data-bind="with: exercises">
<li data-bind="text: name"></li>
</ul>
</li>
</ul>
</div>
Here's this code at jsfiddle:
http://jsfiddle.net/9TrbE/
Thanks!
The exercises property you declared as an object should be an array.
self.workouts = ko.observableArray([
{name: "Workout1", exercises:[
{ name: "Exercise1.1" },
{ name: "Exercise1.2" },
{ name: "Exercise1.3" }
]},
]);
So you can use this view :
<div class="content">
<ul data-bind="foreach: workouts">
<li>
<span data-bind="text: name"> </span>
Remove
<ul data-bind="foreach: exercises">
<li data-bind="text: name"></li>
</ul>
</li>
</ul>
</div>
Declaring :
var exercises = {
name: "Exercise1.1",
name: "Exercise1.2",
name: "Exercise1.3"
};
Is like doing that :
var exercises = {
name: "Exercise1.1",
};
exercises.name: "Exercise1.2";
exercises.name: "Exercise1.3";
Get it with this
Here's this code at jsfiddle
self.workouts = ko.observableArray([
{name: "Workout1", exercises:[
{ name: "Exercise1.1" },
{ name: "Exercise1.2" },
{ name: "Exercise1.3" }
]},
]);
`http://jsfiddle.net/9TrbE/8/

Categories

Resources