I use Web Api and Knockout.js in my project. I want to try like this: if I click the "Home" I want to refresh just main div. So I write this code.
My script in layout.cshtml
<script type="text/javascript">
$(document).ready(function () {
ko.applyBindings(new TalesViewModel());//First load the code is runnig and load the main div
function TalesViewModel() {
var self = this;
self.tales = ko.observableArray();
$.getJSON("/api/tales/", self.tales);
}
$('#home').click(function () {
var Tale = function (TaleName, Content, VoicePath, Tales) {
self = this;
self.TaleName = TaleName;
self.Content = Content;
self.VoicePath = VoicePath;
}
var mapping = {
'tales': {
create: function (options) {
return new Tale(options.data.TaleName, options.data.Content,
options.data.VoicePath);
}
}
}
var data = $.getJSON("/api/tales/", Tale);
var viewModel = ko.mapping.fromjs(data, mapping);
ko.applyBindings(viewModel);
})
})
</script>
I want to refresh this place
<div id="main">
#RenderBody()
</div>
TaleList.cshtml (PartialView)
<div>
<ul data-bind="foreach: tales">
<li>
<div>
<div>Masal Adı</div>
<span data-bind="text: $data.TaleName"></span>
</div>
<div>
<div>İçerik</div>
<span data-bind="text: $data.Content"></span>
</div>
<div>
<div>Ses Dosyası</div>
<span data-bind="text: $data.VoicePath"></span>
</div>
</li>
</ul>
When I clicked Home main div is refresh but no data in here. I think I have to use Knockout something but I don't know how can I do it.
I hope I can explain. Thanks all replies.
Update
If I check with firebug I see this error "TypeError: Object # has no method 'fromjs'"
Update2
I added my first knockout code when I load the project.
This is what you need to do:
Create a js object
var Tale = function (TaleName, Content, VoicePath, Tales) {
self = this;
self.TaleName = TaleName;
self.Content = Content;
self.VoicePath = VoicePath;
}
Create a mapping to convert to your js objects
var mapping = {
'tales': {
create: function(options) {
return new Tale(options.data.TaleName, options.data.Content,
options.data.VoicePath);
}
}
}
Check that your data matches something like below, checking the names match as below:
var data = {"tales" : [{"TaleName": "T1", "Content":"c1", "VoicePath":"v1"}, {"TaleName": "T2", "Content":"c2", "VoicePath":"v2"}]}
var viewModel = ko.mapping.fromJS(data, mapping);
Apply the bindings
ko.applyBindings(viewModel);
Here is a working fiddle with mimicked data
http://jsfiddle.net/dxJpc/1/
Update
You are mixing a combination of getJson and ajax, you only need one.
This can be replaced: (With Ajax)
$.ajax({
type: 'GET',
url: '/Pages/TaleList/',
contentType: 'application/html; charset=utf-8',
dataType: 'html'
})
.success(function (data) {
alert("okey!")
var viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(viewModel);
})
.error(function (req, status, error) {
alert("Error!Occured")
})
With getJSON:
var data = $.getJSON("/api/tales/", Tale);
var viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(viewModel);
Update 3
If you are loading your initial load as you have changed it to, you can simply put this in your on click event:
$('#home').click(function () {
ko.applyBindings(new TalesViewModel());
})
Update 4
Declare the view model in the document ready.
$(document).ready(function () {
var viewModel = new TalesViewModel();
ko.applyBindings(viewModel);
Then change your click to this:
$(document).ready(function () {
viewModel = new TalesViewModel();
Related
The fruit is just so I can make sure it works. Then I will make it work with mlab
Here is what I have in my html page I want it to show in.
<body ng-controller="PackingController as vm">
<h2>List of fruits</h2>
<li ng-repeat="fruit in vm.fruits">{{fruit}}</li>
</body>
In my packingcomponents.js page I have it like this.
class PackingController {
constructor($http) {
this.pack = "are you here";
this.packing = $http({
method: "GET",
url: "/api/camp"
//handels success
}).then(function mySuccess(response) {
console.log(response.data);
return response.data;
//handels errors
}, function myError(response) {
return response.statusText;
});
this.packinglist = this.packing;
console.log(this.packing);
}
}
Then last page I have is my angular_app.js page.
app.controller("PackingController", PackingController)
this.hello = "world";
this.fruits = ["apples", "oranges", "berries"];
Right now I am trying to just get it to work then make it show my packing list on the page.
If you are using AngularJs Modify these part of codes:
1-Use this template for Your controllers
(function() {
"use strict";
angular.module("app")
.controller("PackingController", PackingController);
/* #ngInject */
function PackingController(factory) {
var vm = this;
//-------------------------------variables
vm.fruits = [];
//-------------------------------functions
main();
function main() {
// call factory and get controller's data
}
}
})();
2-Modify your html codes
<div ng-controller="PackingController as vm">
<h2>List of fruits</h2>
<ul>
<li ng-repeat="fruit in vm.fruits">{{fruit}}</li>
</ul>
</div>
Working with the dynamic JavaScript Technology called Knockout, I would like to send new data to my webpage and ask Knockout to do the dynamic UI update for me.
The below example shows a very simple webpage that shows two Scores (P1 and P2). The JavaScript creates a ViewModel() using Knockout. Unfortunately, I only achieved this by providing a JSON-data property. And I don't know how to dynamically load and also dynamically update new score-data.
Now my question: How can I "inject" (i.e. load at first and update at any time) new data to my webpage and Knockout would update the Scores UI dynamically ?
I guess, I would need some sort of...
a) $.getJSON(".... for the initial loading!
b) Post-request (REST) call from anywhere for the data-update
But how do I do a) and b) ???
Thanks for any help on this.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>iKK_ScoreMirror</title>
</head>
<script type='text/javascript' src='Knockout/knockout-3.4.2.js'></script>
<body>
<h3>Game</h3>
<p>Score P1 = <span data-bind="text: scoreP1"></span> </p>
<p>Score P2 = <span data-bind="text: scoreP2"></span> </p>
</body>
<script>
function ViewModel() {
var self = this;
// !!!!!!! Here is the json-data given fix
var jsonData = {
sP1: 13,
sP2: 23
};
self.scoreP1 = ko.observable(jsonData.sP1)
self.scoreP2 = ko.observable(jsonData.sP2)
};
var vm = new ViewModel();
ko.applyBindings(vm);
</script>
</html>
you mean something like this? here is a runnable fiddle https://jsfiddle.net/ca0xv62w/2/
function ViewModel() {
var self = this;
self.scoreP1 = ko.observable('13')
self.scoreP2 = ko.observable('23')
self.loadDataFromServer = function() {
$.ajax({
type: 'POST',
cache: false,
data: {
json: JSON.stringify(data)
},
url: '/echo/json/',
success: function(response) {
self.scoreP1(response.sP1);
self.scoreP2(response.sP2);
}
});
}
}
I am new to knockout.js and am trying to create a simple notification message component. What's happening is that the binding appears to occur, but there are no updates happening to the UI. Below is the code, and I would appreciate any help in locating where this is falling down.
Please note: I am using ASP.NET MVC 5, Knockout.js 3.2.0, Require.js 2.1.14 with AMD for accessing scripts and views.
View - Hub
<div class="row">
<notification-hub></notification-hub>
</div>
<button type="button">Push Me!</button>
#section scripts {
<script src="~/Scripts/Views/Home/index.js" type="text/javascript"></script>
}
Hub Script
require(["ko", "jquery", "ViewModels/notificationMessage", "Components/Notifications/hub", "Plugins/jquery.timeago"], function (ko, jquery, notificationMessage, notificationHub) {
try {
// Register the component.
ko.components.register("notification-hub", {
viewModel: notificationHub,
template: { require: "text!/Components/Notifications/HubItemView" }
});
// Create an instance of the hub and add an inital message.
var hub = new notificationHub();
hub.addMessage(new notificationMessage("Test", "This is a test message.", "2015-02-06 11:00 AM"));
// Bind things up.
ko.applyBindings(hub, $("notification-hub")[0]);
// Create a handler for the button click.
$("button").on("click", function () {
hub.addMessage(new notificationMessage("New Message", "This is a new message", new Date().toLocaleDateString()));
});
}
catch (e) {
$("#displayValues").html("Something went wrong...");
Debug.writeln("Script error: " + e.message);
}
});
ViewModel - Hub
define(["ko", "jquery"], function (ko, jquery) {
// Create the hub's main ViewModel.
function notificationHub() {
var self = this;
// Define the Properties.
self.messages = ko.observableArray();
self.count = ko.computed(function () { return self.messages().length; });
}
// Define the addMessage method.
notificationHub.prototype.addMessage = function (msg) {
var self = this;
// Pop message to the top of the stack.
self.messages().push(msg);
Debug.writeln("Count of message array: " + self.messages().length);
}
return notificationHub;
});
View - Message Model
<p data-bind="if: messages().length == 0">Unfortunately we didn't find any records.</p>
<ul data-bind="foreach: messages">
<li class="notificationMessage">
<span class="timeAgo" data-bind="text: createdDate"></span>
<h2 data-bind="text: title"></h2>
<p data-bind="text: message"></p>
</li>
</ul>
<!-- For debugging purposes -->
<input type="text" data-bind="value: count" />
ViewModel - Message Model
define(["ko"], function (ko) {
// Define the ViewModel for the messages themselves.
return function notificationMessage(title, message, date) {
var self = this;
// Define the Properties.
self.title = title;
self.message = message;
self.createdDate = date;
};
});
Here is my markup:
<section id="Application">
<!-- ko ifnot: initialized -->
<span>Loading...</span>
<!-- /ko -->
<ul data-bind="template:{name: 'clientList', foreach:clients}">
</ul>
<ul data-bind="template:{name: 'storyList', foreach:stories}">
</ul>
</section>
Here is my templates (they are in separate files):
function IncompleteStoriesViewModel() {
//data
var self = this;
self.initialized = ko.observable(false);
self.stories = ko.observableArray();
(function () {
$.ajax({
url: lucidServer.getIncompleteStory(1),
success: function (data) {
ko.mapping.fromJS(data, {}, self.stories);
self.initialized(true);
}
});
})();
};
ko.applyBindings(new IncompleteStoriesViewModel());
function ClientViewModel() {
//data
var self = this;
self.initialized = ko.observable(false);
self.clients = ko.observableArray();
(function () {
$.ajax({
url: lucidServer.getClients(1),
success: function (data) {
ko.mapping.fromJS(data, {}, self.clients);
self.initialized(true);
}
});
})();
};
ko.applyBindings(new ClientViewModel());
My template files are fine, if I call one or the other in the html, they each work individually, but when I try to get them both to show up, only the first one renders, and the second one throws an error that 'stories is not defined' or 'clients is not defined'
I am sure I need to execute this differently, I just can't figure out how. My goal is to have up to 10-15 viewmodels rendering different templates on the same page.
You have to create a view model which will contains all your view models:
function ViewModel(){
var self = this;
self.clientViewModel = new ClientViewModel();
self.storyViewModel = new IncompleteStoriesViewModel();
}
Then apply bindings to the entire page:
ko.applyBindings(new ViewModel());
And adjust html accordingly:
<section id="Application">
<ul data-bind="template:{name: 'clientList', foreach: clientViewModel.clients}">
</ul>
<ul data-bind="template:{name: 'storyList', foreach:storyViewModel.stories}">
</ul>
</section>
Artem's answer is probably the better way, but you do have another option. You can call applyBindings and use the second parameter to specify an element to target.
ko.applyBindings(viewModelA, document.getElementById("one"));
ko.applyBindings(viewModelB, document.getElementById("two"));
This will allow multiple viewmodels to be bound on the page.
I've got an index page that lists taxes in a table. I'm trying to
implement this with ember.js following some of the code in the
contacts example app.
Here is the gist: https://gist.github.com/1494281
When I don't load the content from JSON, by commenting out line 19 of
taxes.js, the table renders correctly. However if I use the content
that I pulled from taxes.json then the table renders without tr and
td elements.
Script:
App.Tax = Ember.Object.extend({});
App.taxesController = Ember.ArrayController.create({
content: [
{name:"tax1",rate:"10",number_id:"TaxIDNum"},
{name:"tax2",rate:"9",number_id:null}
],
newTax: function() {
this.pushObject(App.Tax.create({}));
},
loadTaxes: function() {
console.log('loadTaxes');
var self = this;
$.getJSON('/taxes.json', function(json) {
console.log('got response', taxes);
var taxes = json.map(function(item) {
return self.createTaxFromJSON(item);
});
self.set('content', taxes);
});
},
createTaxFromJSON: function(json) {
console.log("createTaxFromJSON", json.tax);
return App.Tax.create(json.tax);
}
});
App.taxesController.loadTaxes();
App.selectedTaxController = Ember.Object.create({
content: null
});
App.TaxListView = Ember.View.extend({
classNameBindings: ['isSelected'],
click: function() {
var content = this.get('content');
console.log('click', content);
App.selectedTaxController.set('content', content);
},
isSelected: function() {
var selectedItem = App.selectedTaxController.get('content');
var content = this.get('content');
if (content == selectedItem) {
return true;
}
return false;
}.property('App.selectedTaxController.content')
});
App.TaxView = Ember.View.extend({
contentBinding: 'App.selectedContactController.content'
});
HTML:
<script type="text/x-handlebars">
<table>
{{#each App.taxesController.content}}
{{#view App.TaxListView contentBinding="this" tagName="tr"}}
{{#with content}}
<td>{{name}}</td>
<td>{{rate}}</td>
<td>{{number_id}}</td>
<td>
Edit
Delete
</td>
{{/with}}
{{/view}}
{{/each}}
</table>
</script>
JSON:
[{"tax":{"account_id":1,"created_at":"2011-12-16T22:45:43Z","id":1,"name":"CA Sales Tax","number_id":"","rate":10.0,"updated_at":"2011-12-16T22:45:43Z"}},{"tax":{"account_id":1,"created_at":"2011-12-17T01:03:01Z","id":2,"name":"Second Tax","number_id":"EIN29387","rate":0.3,"updated_at":"2011-12-17T01:03:01Z"}}]
When you look at the resulting HTML, you'll notice that ember added tags inside your table. these are the markers for bindings to work
according to the HTML specification, inside a tag there MUST only be , , , tags, everything else is undefined behaviour
to make it work, you'll have to remove the {{#view}} and it should at least render something useful.