- Details
- Written by: Stanko Milosev
- Category: Knockout
- Hits: 2528
/*global google, ko*/
/*jshint esversion: 6 */
/* jshint -W031 */
(function (ns){
    "use strict";
 
    var mapOptions,
        mapCanvas,
        map,
		gpsViewModel;
 
    mapOptions = {
        zoom: 6,
        center: { lat: -34.397, lng: 150.644},
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
 
    mapCanvas = document.getElementById('map-canvas');
 
    if (!map) {
        map = new google.maps.Map(mapCanvas, mapOptions);
		gpsViewModel = new ns.GpsViewModel();
		ko.applyBindings(gpsViewModel);
		google.maps.event.addListener(map, 'click', function (evemt) {
			new google.maps.Circle({ 
				strokeColor: "#FF0000",
				strokeOpacity: 0.8,
				strokeWeight: 2,
				fillColor: "#FF0000",
				fillOpacity: 0.35,
				map,
				center: { lat: gpsViewModel.lat(), lng: gpsViewModel.lng()},
				radius: Math.sqrt(603502) * 100
			});
		});
		
		google.maps.event.addListener(map, 'mousemove', function (event) {
			gpsViewModel.lat(event.latLng.lat());
			gpsViewModel.lng(event.latLng.lng());
		});
    }
}(window.milosev));
gps.js:
/*global window, ko*/
(function (ns) {
	"use strict";
  
  var self;
	
	ns.GpsViewModel = function () {
		self = this;
		
		self.lat = ko.observable();
		self.lng = ko.observable();
		
		return {
			lat: self.lat,
			lng: self.lng
		};
	};
	
}(window.milosev));
Notice line:
radius: Math.sqrt(603502) * 100
That was just copy / paste, otherwise radius is in meters Source download from here. Live example:
Langitude:
Longitude:
- Details
- Written by: Stanko Milosev
- Category: Knockout
- Hits: 2481
<!DOCTYPE html>
<html>
	<head>
		<script type="text/javascript" src="js/index.js"></script>
		<script type="text/javascript" src="js/lib/knockout-3.5.1.js"></script>	
		<script type="text/javascript" src="js/lib/jquery-3.4.1.min.js"></script>	
	</head>
	
	<body onload="DoApply()">
		Cities:
		<span data-bind="template: {name: 'cities-template', foreach: cities}"></span>
		<script type="text/html" id="cities-template" >
			<br/>
			<input data-bind="id: id, name: name" type="checkbox">
			<label data-bind="for: name, text: name"></label>
		</script>			
	</body>
</html>
JS:
function MyViewModel() {
	var self = this;
	self.cities = ko.observableArray([]);
	
	$.getJSON("cities.json", function(data) { 
		data.forEach(function (item, index) {
			self.cities.push({name: item.Name, id:item.ID});	
		});
		
	})
}
function DoApply() {
	ko.applyBindings(new MyViewModel());
}
Where cities.json looks like:
[
	{
		"ID": 0,
		"Name": "Bonn"
	},
	{
		"ID": 0,
		"Name": "Petrovaradin"
	},
	{
		"ID": 0,
		"Name": "Novi Sad"
	},
	{
		"ID": 0,
		"Name": "Balingen"
	}
]
Live example see here.
---
Edit: observableArray must be global, something like ns.cities = ko.observableArray([]);, and pushed should be observable:
/*global window, ko*/
(function (ns) {
    "use strict";
    ns.CitiesViewModel = function () {
        var self = this,
            getCities = new GetCities(),
            city = ko.observable();
        ns.cities = ko.observableArray();
        function GetCities() {
            $.getJSON("api/cities", function (data) {
                data.forEach(function (item, index) {
                    city({ name: item.Name, id: item.ID });
                    ns.cities.push(city());
                });
            });
        }
        return {
            myCities: getCities
        }
    }
}(window.milosev));
---
Or even better and make it part of CitiesViewModel:
/*global window, ko, $*/
(function (ns) {
    "use strict";
    ns.CitiesViewModel = function () {
        var self = this,
            getCities = new GetCities(),
            city = ko.observable();
        function GetCities() {
            self.cities = ko.observableArray();
            $.getJSON("api/cities", function (data) {
                data.forEach(function (item, index) {
                    city({ name: item.Name, id: item.ID });
                    self.cities.push(city());
                });
            });
            return self.cities;
        }
        return {
            cities: getCities
        };
    };
}(window.milosev));
    
    
    
        - Details
- Written by: Stanko Milosev
- Category: Knockout
- Hits: 4227
Example which I am using when I want to see which model I am sending to knockout.
HTML:
    <body>
        <div data-bind="text: function() {debugger; return myText}()"></div>
    </body>
JS:
/*global ko*/
(function () {
    "use strict";
    function MyModel() {
        var self = this;
        self.myText = ko.observable("Test");
    }
    MyModel = new MyModel();
    ko.applyBindings(MyModel);
}());
Notice in HTML line:
<div data-bind="text: function() {debugger; return myText}()"></div>
In that line you can see debugger, and also return, which will force function to return value. Now you can debug knockout.
- Details
- Written by: Stanko Milosev
- Category: Knockout
- Hits: 4470
In custom bindings you can pass whole object, parse it and later use it, also you can pass a function (like observable for example).
HTML
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="/knockout-3.3.0.js"></script>
    <script type="text/javascript" src="/index.ko.extension.js" defer></script>
    <script type="text/javascript" src="/index.js" defer></script>
</head>
<body>
    <div data-bind="myBind: {propertyOne: testOne, propertyTwo: testTwo}"></div>
</body>
</html>
Here notice part:
<div data-bind="myBind: {propertyOne: testOne, propertyTwo: testTwo}"></div>
Now index.js:
/*global window, ko*/
function MyLog(msg) {
    function doTheLog(msg) {
        console.log(msg);
    }
    return {
        doTheLog: doTheLog
    }
};
window.doSomething = new MyLog();
window.testOne = "test one";
window.testTwo = "test two";
ko.applyBindings();
Here notice that I have created global variables testOne and testTwo, I need them for binding.
index.ko.extension.js:
/*global ko, console*/
/*jslint unparam: true*/
ko.bindingHandlers.myBind = {
    init: function (element, valueAccessor) {
        "use strict";
        var myObjExample = ko.unwrap(valueAccessor());
        doSomething.doTheLog(myObjExample.propertyOne);
        doSomething.doTheLog(myObjExample.propertyTwo);
    }
};
/*jslint unparam: false*/
Here notice:
var myObjExample = ko.unwrap(valueAccessor());
With that I am actually parsing my object.
Unit test looks like this:
/*global describe, it, expect, beforeEach, ko, window, document, $*/
describe("my bind", function () {
    "use strict";
    var sut;
    beforeEach(function () {
        //'<div data-bind="myBind: {propertyOne: testOne, propertyTwo: testTwo}"></div>'
        var myDiv = document.createElement('div');
        myDiv.setAttribute("data-bind", "myBind: {propertyOne: testOne, propertyTwo: testTwo}");
        document.body.appendChild(myDiv);
        window.testOne = "test one";
        window.testTwo = "test two";
        window.doSomething = jasmine.createSpyObj('MyLog', ['doTheLog']);
        ko.applyBindings();
    });
    it("gets object from value acessor", function () {
        expect(window.doSomething.doTheLog).toHaveBeenCalled();
    });
});
Example download from here.
---
Actually, better unit test looks like:
/*global describe, it, expect, beforeEach, ko, window, document*/
describe("my bind", function () {
    "use strict";
    var sut,
        testOne,
        testTwo;
    beforeEach(function () {
        var myDiv = document.createElement('div');
        testOne = jasmine.createSpy("testOne");
        testTwo = jasmine.createSpy("testTwo");
        myDiv.setAttribute("data-bind", "myBind: {testOne: testOne, testTwo: testTwo}");
        document.body.appendChild(myDiv);
        window.doSomething = jasmine.createSpyObj('MyLog', ['doTheLog']);
        ko.applyBindings({testOne: testOne, testTwo: testTwo});
    });
    it("gets object from value acessor", function () {
        expect(window.doSomething.doTheLog).toHaveBeenCalled();
    });
});
Notice first my binding:
myDiv.setAttribute("data-bind", "myBind: {testOne: testOne, testTwo: testTwo}");
Then the apply bindings:
ko.applyBindings({testOne: testOne, testTwo: testTwo});
Version with this test download from here.