Create ko.observableArray from JSON object in Knockout JS - json

I have JSON object loaded to my view model. I want to push that into an observableArray.
function viewModel()
{
var self = this;
self.details = [{"id":1,"first_name":"fname1","last_name":"lname1","salary":1000.0},
{"id":2,"first_name":"fname2","last_name":"lname2","salary":2000.0},
{"id":3,"first_name":"fname3","last_name":"lname3","salary":3000.0}];
self.emp = ko.observableArray([new Model(self.details[0]),new Model(self.details[1]),new Model(self.details[2])]);
//This method works, but is very inefficient...
}
ko.applyBindings(new viewModel());
The solution I found was to feed each element individually, which is not practical.
I'm using JQuery. I found some solutions using knockout.mapping plugin. But I'm unable to add that plugin to my Eclipse workspace correctly.
I'm new to Knockout. Please help me find a solution to add the entire object to the observableArray.

I would probably use the mapping plugin personally, but this should also work
function viewModel()
{
var self = this;
self.details = [{"id":1,"first_name":"fname1","last_name":"lname1","salary":1000.0},
{"id":2,"first_name":"fname2","last_name":"lname2","salary":2000.0},
{"id":3,"first_name":"fname3","last_name":"lname3","salary":3000.0}];
var mapped = self.details.map(m => new Model(m));
//or
//var mapped = self.details.map(function(m) {return new Model(m);});
self.emp = ko.observableArray(mapped);
}
ko.applyBindings(new viewModel());

Related

TVML listItemLockup click event

I'm using the 'Compilation.xml' template from the TVMLCatalog
I'd like to add a button click event to a 'listItemLockup'
<listItemLockup>
<ordinal minLength="2" class="ordinalLayout">0</ordinal>
<title>Intro</title>
<subtitle>00</subtitle>
<decorationLabel>(3:42)</decorationLabel>
</listItemLockup>
I've tried adding:
App.onLaunch = function(options) {
var templateURL = 'http://localhost:8000/hello.tvml';
var doc = getDocument(templateURL);
//doc.addEventListener("select", function() { alert("CLICK!") }, false);
var listItemLockupElement = doc.getElementsByTagName("listItemLockup");
listItemLockupElement.addEventListener("select", function() { alert("CLICK!") }, false);
}
addEventListener
void addEventListener (in String type, in Object listener, in optional Object extraInfo)
Is "select" the correct type?
I've been using the following tutorials
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-with-swift/
http://jamesonquave.com/blog/developing-tvos-apps-for-apple-tv-part-2/
Update
I'm getting an error
ITML <Error>: doc.getElementsByTagName is not a function. (In 'doc.getElementsByTagName("listItemLockup")', 'doc.getElementsByTagName' is undefined) - http://localhost:8000/main.js - line:27:58
I tried adding this to the 'onLaunch'
var listItemLockupElements = doc.getElementsByTagName("listItemLockup");
for (var i = 0; i < listItemLockupElements.length; i++) {
//var ele = listItemLockupElements[i].firstChild.nodeValue;
listItemLockupElements[i].addEventListener("select", function() { alert("CLICK!") }, false);
}
I'll see about the error first
Cross Post: https://forums.developer.apple.com/thread/17859
More common example I have seen by Apple is to define a single overall listener like:
doc.addEventListener("select", Presenter.load.bind(Presenter));
In your xml, assign unique ids to elements, or give them ways to identify them.
For example, the beginning would be something like:
load: function(event) {
var self = this,
ele = event.target,
attr_id = ele.getAttribute("id"),
audioURL = ele.getAttribute("audioURL"),
videoURL = ele.getAttribute("videoURL")
And then you can do whatever you want with your item.
if(audioURL && (event.type === "select" || event.type === "play")) {
//
}
My advice would be to study the Presenter.js file more carefully for this pattern.
Edit:
Answering your "Update" related to doc.getElementsByTagName is not a function. "doc" does not actually exist, but the general pattern is to get it with
var doc = getActiveDocument();
I assumed you would know the above.
Does that fix it?
var listItemLockupElement = doc.getElementsByTagName("listItemLockup”);
In this case, the listItemLockupElement is a NodeList, not an element. You can either iterate through the list and add an event listener to each listItemLockup, or you could add the event listener to the containing element.
When addressing items in a NodeList, you use the item(i) method rather than the standard array access notation:
listItemLockupElements.item(i).addEventListener("select", function() { })
See: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/item
Adding event listeners is straightforward if you're using atvjs framework.
ATV.Page.create({
name: 'mypage',
template: your_template_function,
data: your_data,
events: {
select: 'onSelect',
},
// method invoked in the scope of the current object and
// 'this' will be bound to the object at runtime
// so you can easily access methods and properties and even modify them at runtime
onSelect: function(e) {
let element = e.target;
let elementType = element.nodeName.toLowerCase();
if (elementType === 'listitemlockup') {
this.doSomething();
}
},
doSomething: function() {
// some awesome action
}
});
ATV.Navigation.navigate('mypage');
Disclaimer: I am the creator and maintainer of atvjs and as of writing this answer, it is the only JavaScript framework available for Apple TV development using TVML and TVJS. Hence I could provide references only from this framework. The answer should not be mistaken as a biased opinion.

Changing the pitch of the sound of an HTML5 audio node

I would like to change the pitch of a sound file using the HTML 5 Audio node.
I had a suggestion to use the setVelocity property and I have found this is a function of the Panner Node
I have the following code in which I have tried changing the call parameters, but with no discernible result.
Does anyone have any ideas, please?
I have the folowing code:
var gAudioContext = new AudioContext()
var gAudioBuffer;
var playAudioFile = function (gAudioBuffer) {
var panner = gAudioContext.createPanner();
gAudioContext.listener.dopplerFactor = 1000
source.connect(panner);
panner.setVelocity(0,2000,0);
panner.connect(gainNode);
gainNode.connect(gAudioContext.destination);
gainNode.gain.value = 0.5
source.start(0); // Play sound
};
var loadAudioFile = (function (url) {
var request = new XMLHttpRequest();
request.open('get', 'Sounds/English.wav', true);
request.responseType = 'arraybuffer';
request.onload = function () {
gAudioContext.decodeAudioData(request.response,
function(incomingBuffer) {
playAudioFile(incomingBuffer);
}
);
};
request.send();
}());
I'm trying to achieve something similar and I also failed at using PannerNode.setVelocity().
One working technique I found is by using the following package (example included in the README): https://www.npmjs.com/package/soundbank-pitch-shift
It is also possible with a biquad filter, available natively. See an example here: http://codepen.io/qur2/pen/emVQwW
I didn't find a simple sound to make it obvious (CORS restriction with ajax loading).
You can read more at http://chimera.labs.oreilly.com/books/1234000001552/ch04.html and https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode.
Hope this helps!

backbone.js fetch json success will not hit

i use fetch from backbone.js to load a json model but success will not hit.
var DialogModel = Backbone.Model.extend({
url : function() {
return '/messages/getDialog';
},
parse : function(res) {
return res.dialog;
}
});
var DialogView = Backbone.View.extend({
el: $("#page"),
initialize: function() {
var onDataHandler = function() {
this.render();
};
this.model = new DialogModel();
this.model.fetch({ success : onDataHandler});
},
render: function(){
var data = {
dialogModel : this.model
};
var form = new Backbone.Form({
model: data
});
$(this.el).html(form.render().el);
}
});
What happens now:
DialogView initialize is called.
this.model.fetch is called but the onDataHandler function will not be hit if success.
/messages/getDialog throws a json file back.
The json file is loading well as i can see in the network browser.
Thanks for your help!
Oleg
The problem you're having is due to a typical JS gotcha and not related to Backbone itself. Try
var that = this;
this.model.fetch({
success : function () {
that.render();
}
});
The way you're currently passing onDataHandler is problematic as it will cause this to refer to the global object instead of the DialogView, when the function is called.
This fiddle demonstrates the problematic version vs one that works.
(You may also want to take a look at JS strict mode which can shield you from this type of errors.)
Even better is to listen for an event:
this.model.on("sync", this.render).fetch();
I ran across this question while looking for something else, but the currently accepted answer drives me nuts. There's no good reason to be sprinkling this and that all over your code. Backbone (underscore) includes a context parameter that you can bind to.
that = this makes no sense. If you must implement obsolete 2007-era Crockford patterns, then say var self = this. Saying that = this is like saying left = right. Everyone Stop.

IWcfPolicy - add message headers on the fly

Is it somehow possible to add header info (or querystrings) to a wcf request on the fly?
I've been messing around a bit with the IWcfPolicy like this:
var xmlObjectSerializer = new DataContractSerializer(typeof(string));
var addressHeader = AddressHeader.CreateAddressHeader("client", "http://tempuri.org/", "someValue", xmlObjectSerializer);
var endpointAddress = new EndpointAddress(new Uri(url), new AddressHeader[] { addressHeader });
invocation.ChannelHolder.ChannelFactory.Endpoint.Address = endpointAddress;
invocation.Proceed();
this does not work however. Any help would be very much apperciated.
ok so here's how to do it:
using (var scope = new OperationContextScope((IContextChannel) (invocation.ChannelHolder.Channel)))
{
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty
()
{
Headers =
{
{"client", LicenseManager.Instance.GetCurrentLicense().LicenseKey}
}
};
invocation.Proceed();
}
This code goes into Apply method of the IWcfPolicy implementation.
Found solution because of this post: how to add a custom header to every wcf call

Binding JSON string to ListView in Metro apps?

I have a metro application(HTML5 & WinJS) in which am trying to display service data . Actually here am retrieving JSON data from my service but am unable to bind this data into listview . Anyone give me some working example.
Thank you.
You can use the WinJS.xhr() for this. You can read more about it on this link https://msdn.microsoft.com/pt-br/library/windows/apps/br229787.aspx and here is an example:
var path = "data/file.json";
function getData(path) {
WinJS.xhr({ url: path }).then(
function (response) {
var json = JSON.parse(response.responseText);
// Since this is an asynchronous function, you can't
// return the data, so you can:
// 1) retrieve the data to a namespace once the app loads.
var list = new WinJS.Binding.List(json);
Somenomespace.data = list;
// 2) or do all the binding inside the function.
var listView = document.getElementById("listViewID");
listView.winControl.itemDataSource = list.dataSource;
});
}
If you use the built in JSON.parse(jsonString) function you can loop through the content using a normal for loop as it then is a normal object and add it as usuall. Just remember to process or render the data.
Her is an example from code i had in a search page using listview:
var response = JSON.parse(data) ;
var originalResults = new WinJS.Binding.List();
for (x in response) {
originalResults.push(response[x]);
}
this.populateFilterBar(element, originalResults);
this.applyFilter(this.filters[0], originalResults);