Create ko.observableArray from JSON Object in knockout - javascript

I just started using knockout.js and it works great with normal bidings. I have a problem with observableArray.
I want to create an observableArray and assign to it a JSON data from Google Feed API. Here is the JSON format https://developers.google.com/feed/v1/devguide#resultJson
google.load("feeds", "1"); // Loads Google Feed API
function FeedViewModel()
{
// Data
var self = this;
self.allEntries = null;
// Example property, and it works
self.feedHead = ko.observable("BBC News");
var feed = new google.feeds.Feed("feeds.feedburner.com/BBCNews");
feed.setResultFormat(google.feeds.Feed.JSON_FORMAT);
feed.includeHistoricalEntries();
feed.setNumEntries(30);
// Loads feed results
feed.load(function (result) {
if (!result.error) {
self.allEntries = ko.observableArray(result.feed.entries);
// accessing the title from here is OK
alert(self.allEntries()[1].title);
}
});
}
In the above example, accessing the array from the ViewModel is OK but I need to display it in the view (to the browser) using foreach:allEntries
<h2 data-bind="text: feedHead">Latest News</h2>
<!-- ko foreach:allEntries -->
<div class="lists">
</div>
<!-- /ko -->
But nothing the ko foreach loop returns nothing. The observable feedHead is OK.
Also I dont have any JS error. Any help..

Try declaring ( where you have the // Data )
self.allEntries = ko.observableArray([]);
then in the load...
self.allEntries(result.feed.entries);

Related

How to call function dynamically in JQuery

I've set of html codes, I want to have a function for each set where I can pull some data or do some activities, so basically I need to be calling function according to the html codes present in DOM, suppose I've header section I want to collect menu items and I've sliders where I want to collect slider information, So I need to call header function to do the activity accordingly and slider function to do the activity, I went across some info about eval() but I guess it has lot of demerits and is being obsolete. Please suggest me how can I achieve it.
HTML Code:
Header
<div class="header" data-nitsid="1">
<div class="branding">
<h1 class="logo">
<img src="images/logo#2x.png" alt="" width="25" height="26">NitsOnline
</h1>
</div>
<nav id="nav">
<ul class="header-top-nav">
<li class="has-children">
Home
</li>
</ul>
</nav>
</div>
Slider
<div id="slideshow" data-nitsid="2">
<div class="revolution-slider">
<ul> <!-- SLIDE -->
<!-- Slide1 -->
<li data-transition="zoomin" data-slotamount="7" data-masterspeed="1500">
<!-- MAIN IMAGE -->
<img src="http://placehold.it/1920x1200" alt="">
</li>
</ul>
</div>
</div>
Now I want to collect data from both elements and pass the data to my views of laravel framework where it will generate a popup for each section for editing purpose.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design.nits();
}
var design = {};
design.1 = function() {
// do ajax request to views of header
}
design.2 = function() {
// do ajax request to views of slider
}
You canot use literal number as a property name. If you want to call property 1 of object design use design[1] instead. Also, you cannot assing property to non-initialized variable, you must use var design = {}; to make it object. If your property of design object is stored in nits variable, then call it as design[nits]();. Also, next time don't forget to test your code before posting it here. You've forget ) after your first function.
$('.page-content-wrapper').find('[data-nitsid]').each(function() {
// getting data to call function
var nits = $(this).data("nitsid");
// calling function
design[nits]();
});
var design = {};
design[1] = function() {
// do ajax request to views of header
};
design[2] = function() {
// do ajax request to views of slider
};
You want to use design[nits]();.
This will get the property nits of design and execute it with ().
But there is another problem. Your design will be declared after the each loop, so it is not available inside. You have to place it before.
$(function() {
var design = {};
design.funcOne = function() {
alert("funcOne called");
}
design.funcTwo = function() {
alert("funcTwo called");
}
$('div[data-nitsid]').each(function() {
var nits = $(this).data("nitsid");
design[nits]();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-nitsid="funcOne">
I will call 'funcOne'!
</div>
<div data-nitsid="funcTwo">
I will call 'funcTwo'!
</div>

Pass Angular typeahead object result to another function in controller

In this scenario I'm using the ui-bootstrap typeahead to capture an object from an external api. Using the select callback I'm getting that object and have the results set in a separate function within my controller.
The issue is that I want to take those results and send them off to a separate api with a click function I already have set up. My question is how do i get the results of the type-ahead into the click function to post? The user flow is as follows.
<div>
<input type="text" placeholder="Find A Game"
typeahead-on-select="setGames($item)"
ng-model="asyncSelected"
typeahead="test.name for test in getGames($viewValue)"
typeahead-loading="loadingLocations" typeahead-min-length="3"
typeahead-wait-ms="500" typeahead-select-on-blur="true"
typeahead-no-results="noResults">
</div>
<div ng-show="noResults">
No Results Found
</div>
<button ng-disabled="!asyncSelected.length"
ng-click="addtodb(asyncSelected)">Add To Database</button>
As you can see the label is set to the items name and this works fine. When the user selects the name I then use typeahead-on-select="setGames($item)" to send off the entire object to its own funtion. From there I want to take the object and pass it to another function that you can see within the button tags ng-click. I currently have it passing the model, but what I really want is to pass the entire object within $item from the select event. So far my controller looks like this:
angular.module('2o2pNgApp')
.controller('GiantCtrl', function ($scope, $http, TermFactory, $window, SaveFactory) {
$scope.getGames = function(val) {
return $http.jsonp('http://www.example.com/api/search/?resources=game&api_key=s&format=jsonp&limit=5&json_callback=JSON_CALLBACK', {
params: {
query: val
}
}).then(function(response){
return response.data.results.map(function(item){
return item;
});
});
};
$scope.setGames = function (site) {
var newsite = site;
};
$scope.addtodb = function (asyncSelected, newsite) {
TermFactory.get({name: asyncSelected}, function(data){
var results = data.list;
if (results === undefined || results.length === 0) {
SaveFactory.save({vocabulary:'5', name:newsite.name, field_game_id:newsite.id}, function(data) {
$window.alert('All Set, we saved '+asyncSelected+' into our database for you!')
});
} else {
// do stuff
});
}
});
No matter what I do I cant seem to pass the entire $item object into this click function to post all the info i need.
Via New Dev in Comments:
$item is only available locally for typeahead-on-select... you can
either assign it to some model within your controller, or, in fact,
make the model of typeahead to be the item: typeahead="test as
test.name for test in getGames($viewValue)" – New Dev

Having issues tying together basic javascript chat page

I have the skeleton of a chat page but am having issues tying it all together. What I'm trying to do is have messages sent to the server whenever the user clicks send, and also, for the messages shown to update every 3 seconds. Any insights, tips, or general comments would be much appreciated.
Issues right now:
When I fetch, I append the <ul class="messages"></ul> but don't want to reappend messages I've already fetched.
Make sure my chatSend is working correctly but if I run chatSend, then chatFetch, I don't retrieve the message I sent.
var input1 = document.getElementById('input1'), sendbutton = document.getElementById('sendbutton');
function IsEmpty(){
if (input1.value){
sendbutton.removeAttribute('disabled');
} else {
sendbutton.setAttribute('disabled', '');
}
}
input1.onkeyup = IsEmpty;
function chatFetch(){
$.ajax({
url: "https://api.parse.com/1/classes/chats",
dataType: "json",
method: "GET",
success: function(data){
$(".messages").clear();
for(var key in data) {
for(var i in data[key]){
console.log(data[key][i])
$(".messages").append("<li>"+data[key][i].text+"</li>");
}
}
}
})
}
function chatSend(){
$.ajax({
type: "POST",
url: "https://api.parse.com/1/classes/chats",
data: JSON.stringify({text: $('input1.draft').val()}),
success:function(message){
}
})
}
chatFetch();
$("#sendbutton").on('click',chatSend());
This seems like a pretty good project for Knockout.js, especially if you want to make sure you're not re-appending messages you've already sent. Since the library was meant in no small part for that sort of thing, I think it would make sense to leverage it to its full potential. So let's say that your API already takes care of limiting how many messages have come back, searching for the right messages, etc., and focus strictly on the UI. We can start with our Javascript view model of a chat message...
function IM(msg) {
var self = this;
self.username = ko.observable();
self.message = ko.observable();
self.timestamp = ko.observable();
}
This is taking a few liberties and assuming that you get back an IM object which has the name of the user sending the message, and the content, as well as a timestamp for the message. Probably not too far fetched to hope you have access to these data elements, right? Moving on to the large view model encapsulating your IMs...
function vm() {
var self = this;
self.messages = ko.observableArray([]);
self.message = ko.observable(new IM());
self.setup = function () {
self.chatFetch();
self.message().username([user current username] || '');
};
self.chatFetch = function () {
$.getJSON("https://api.parse.com/1/classes/chats", function(results){
for(var key in data) {
// parse your incoming data to get whatever elements you
// can matching the IM view model here then assign it as
// per these examples as closely as possible
var im = new IM();
im.username(data[key][i].username || '');
im.message(data[key][i].message || '');
im.timestamp(data[key][i].message || '');
// the ([JSON data] || '') defaults the property to an
// empty strings so it fails gracefully when no data is
// available to assign to it
self.messages.push(im);
}
});
};
}
All right, so we have out Javascript models which will update the screen via bindings (more on that in a bit) and we're getting and populating data. But how do we update and send IMs? Well, remember that self.message object? We get to use it now.
function vm() {
// ... our setup and initial get code
self.chatSend = function () {
var data = {
'user': self.message().username(),
'text': self.message().message(),
'time': new Date()
};
$.post("https://api.parse.com/1/classes/chats", data, function(result) {
// do whatever you want with the results, if anything
});
// now we update our current messages and load new ones
self.chatFetch();
};
}
All right, so how do we keep track of all of this? Through the magic of bindings. Well, it's not magic, it's pretty intense Javascript inside Knockout.js that listens for changes and the updates the elements accordingly, but you don't have to worry about that. You can just worry about your HTML which should look like this...
<div id="chat">
<ul data-bind="foreach: messages">
<li>
<span data-bind="text: username"></span> :
<span data-bind="text: message"></span> [
<span data-bind="text: timestamp"></span> ]
</li>
</ul>
</div>
<div id="chatInput">
<input data-bind="value: message" type="text" placeholder="message..." />
<button data-bind="click: $root.chatSend()">Send</button>
<div>
Now for the final step to populate your bindings and keep them updated, is to call your view model and its methods...
$(document).ready(function () {
var imVM = new vm();
// perform your initial search and setup
imVM.setup();
// apply the bindings and hook it all together
ko.applyBindings(imVM.messages, $('#chat')[0]);
ko.applyBindings(imVM.message, $('#chatInput')[0]);
// and now update the form every three seconds
setInterval(function() { imVM.chatFetch(); }, 3000);
});
So this should give you a pretty decent start on a chat system in an HTML page. I'll leave the validation, styling, and prettifying as an exercise to the programmer...

Using Knockout with repeated user controls

I have a web page that contains a list of games. Each game is presented by a user control, that contains a few labels that hold the properties of the game (time, scores, players, etc.). So the same user control is repeated a few times on the page.
The data changes every minute to support live covarage of the game.
I was hoping to use knockout to update all labels in the user control, but since every user control should bind to a different game data, and a user control cannot have its own view model, I dont know what is the best approach to this scenario.
I need something like a dynamic ViewModel and a dynamic data-bind attributes, but I couldnt find any information on the subject.
Here is a demonstration of the template binding using both data and foreach with the same template. You can see in the JS that the data is the type, a game, but we are dislpaying them separately in the HTML.
HTML
<!-- ko if: favoriteGame -->
<h1>Favorite Game</h1>
<div data-bind="template: { name: 'gameTemplate', data: favoriteGame }"></div>
<!-- /ko -->
<h1>All Games</h1>
<div data-bind="template: { name: 'gameTemplate', foreach: games }"></div>
<script type="text/ko" id="gameTemplate">
<div>
<span class="gameName" data-bind="text: name"></span>
<span data-bind="text: publisher"></span>
<input data-bind="value: score" />
<button data-bind="click: $parent.favoriteGame">Favorite</button>
</div>
</script>
Javascript
var Game = function(data) {
this.name = ko.observable(data.name || "");
this.publisher = ko.observable(data.publisher || "");
this.score = ko.observable(data.score || 0);
};
var ViewModel = function(init) {
var self = this;
self.favoriteGame = ko.observable();
self.games = ko.observableArray(ko.utils.arrayMap(init, function(g) {
return new Game(g);
}));
};
Note that the click: $parent.favoriteGame binding selects the favorite game directly. Knockout passes the current context as the first parameter to function bindings, and since observables are functions, this updates the observable directly, without needing a wrapper function.
You can take a look at this in this fiddle. Its not perfectly clear what you where after, you don't have any code in your question. I hope this isn't too far off.

simple Flickr application with Knockout.js doesn't work (JSBin prepared)

Now I'm writing a simple application which get five photos from Flickr and display the titles as list. At first I tried #current_photos and this works good, but when I use Knockout.js(#currentPhotos), this doesn't work.
root = exports ? this
class root.Flickr
constructor: ->
#photos = []
$.getJSON(
'http://www.flickr.com/services/rest/?jsoncallback=?'
format : 'json'
method : 'flickr.photos.search'
api_key : '7965a8bc5a2a88908e8321f3f56c80ea'
user_id : '29242822#N00'
per_page : 5
).done((data) =>
$.each data.photos.photo, (i, item) =>
#photos.push item
)
root = exports ? this
class root.PhotoListViewModel
index = null
currentPhotos = []
constructor: ->
flickr = new Flickr
# #current_photos = flickr.photos ###### WORKS GOOD
flickr.photos = ko.observableArray []
#currentPhotos = ko.computed ->
flickr.photos
HTML is as below:
<body>
<h4>Photo List</h4>
<ul data-bind="foreach: currentPhotos">
<li>
title: <span data-bind="text: title"> </span>
</li>
</ul>
</body>
I created JSBin page as below:
http://jsbin.com/avazak/7/
Thanks for your kindness.
Because of how the dependency tracking works in computed observable:
While your evaluator function is running, KO keeps a log of any observables (or computed observables) that your evaluator reads the value of.
So you need to call your observables inside the computed it is not enough the reference them:
#currentPhotos = ko.computed ->
flickr.photos()
And I would suggets that you declare the #photos as ko.observableArray inside the Flickr object not in the PhotoListViewModel
Demo JSFiddle.

Categories