Knockout binding from a JSON data string - html

I'm currently using Knockout to render my HTML page, but I'm stuck when I'm trying to render my HTML when the data is stored in a simple JSON file.
The Json file is here:
{
"name": "Office Web Controls 2014"
}
Here's the function to load my Json string:
<script type="text/javascript">
function AppViewModel() {
this.data = { };
$.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
this.data = ko.mapping.fromJSON(retrievedData);
console.log(this.data);
});
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
</script>
And I would like to bind it to the following HTML:
<div data-bind="text: data.name">
</div>
I've tried very different things but none are working, so if anybody has an idea on how to accomplish this.

Finally, after a long search, I've managed to find the solution.
For anyone who's intrested, here it is:
<div data-bind="template: {name: 'OfficeWebControls-Title', data: ribbonViewModel}">
</div>
And finally the script:
<script type="text/javascript">
var ribbonViewModel;
$.getJSON("Resources/Data/Ribbon.json", function(data) {
ribbonViewModel = ko.mapping.fromJS(data);
ko.applyBindings(ribbonViewModel);
});
</script>

The reason it wasn't working is two fold:
The this pointer in the call back function is not pointing to your vm
Resources:
jQuery/JavaScript "this" pointer confusion
How does the "this" keyword work?
The data property of your vm needs to be converted to an observable
The $.getJSON call will execute asynchronously and the response will be handled after the ko.applyBindings call. This means that you'll be changing the value of the data property after it's bound to the UI. For the UI to receive changes after it is bound the properties on the view model will need to be wrapped in observables.
Example
function AppViewModel() {
//remember the this pointer for the call back handler
var self = this;
//set default data to an observable
self.data = ko.observable(null);
$.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
//use self to reference properties on the vm in a call back handler
self.data(retrievedData);
console.log(self.data());
});
}
ko.applyBindings(new AppViewModel());
For this to work the view will also need to change.
<!-- ko if:data -->
<div data-bind="text: data().name"></div>
<!-- /ko -->
fiddle

Related

How to pass varaiable in HTML functions through jquery

this is my html code. group.participants is an array.
result +=`<button class="gsb-${group.id}" onclick="demo(${group.participants})">`+"DEMO"+`</button><br/>`;
this is my simple javascript code to display the array from the parameter
function demo(participants){
alert(participants);
}
this shows me the error
Uncaught SyntaxError: Unexpected end of input
may I know what is the problem
With Jquery you can use the following to pass data to a selector
$(`.gsb-${group.id}`).data(group.participants);
to recover it you just have to call data() method
$(`.gsb-${group.id}`).data();
Finally like each group have different participants, you will have to append first the group button before add the data to it
result.append(`<button class="gsb-${group.id}" onclick="demo(${group.id})">`+"DEMO"+`</button><br/>`);
$(`.gsb-${group.id}`).data(group.participants);
function demo(groupId) {
var participants = $(`.gsb-${groupId}`).data();
console.log(participants);
}
var result = $('#result');
var group = {
id:1,
participants:[
{name:'test1'},
{name:'test2'}
]
}
result.append(`<button class="gsb-${group.id}" onclick="demo(${group.id})">`+"DEMO"+`</button><br/>`);
$(`.gsb-${group.id}`).data(group.participants);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result"></div>

vue.js json object array as data

aye folks!
I'm currently learning to do stuff with vue.js. unfortunately i'm stuck atm. what i want to do is sending a request to my sample API which responds with a simple json formatted object.
I want to have this object as data in my component – but it doesn't seem to do that for whatever reason.
Ofc i tried to find a solution on stackoverflow but maybe i'm just blind or this is just like the code other people wrote. i even found this example on the official vue website but they're doing the same thing as i do .. i guess?
btw. When i run the fetchData() function in a separate file it does work and i can access the data i got from my API. no changes in the code .. just no vue around it. i'm really confused right now because i don't know what the mistake is.
code:
var $persons = [];
and inside my component:
data: {
persons: $persons,
currentPerson: '',
modal: false
},
created: function() {
this.fetchData()
},
methods: {
fetchData: function () {
var ajax = new XMLHttpRequest()
ajax.open('GET', 'http://api.unseen.ninja/data/index.php')
ajax.onload = function() {
$persons = JSON.parse(ajax.responseText)
console.log($persons[0].fname)
}
ajax.send()
}
},
[...]
link to the complete code
First, make sure that the onload callback is actually firing. If the GET request causes an error, onload won't fire. (In your case, the error is CORS-related, see this post suggested by #Pradeepb).
Second, you need to reference the persons data property directly, not the $persons array that you initialized persons with.
It would look like this (inside your fetchData method):
var self = this;
ajax.onload = function() {
self.persons = JSON.parse(ajax.responseText)
console.log($persons[0].fname)
}

Expression in ng-controller for a JSON-Objects with AngularJS and Ionic

I parse JSON objects to create html elements. In my case, I create from json file Buttons:
{
"type": "button",
"id": "comButton",
"icon": "ion-chatboxes",
"name": "Communication",
"onclick": "",
"controller": "somemthctrl",
"ngclick": "launchSomemethod()",
"color": "white",
"backgroundcolor": "#ff5db1",
"font-size": "20px"
}
Controller:
myApp.controller('generateButtonCtrl', function ($scope, $http) {
$http.get('JSON/buttons.json').success(function(data){
$scope.components = data;
});
});
From the HTML page, I call the components from the json file:
<a ng-repeat="component in components"
style="color:{{component.color}}; background-color:{{component.backgroundcolor}} "
id="{{component.id}}"
class="{{component.type}}"
href="{{component.onclick}}"
ng-click="{{component.ngclick}}"
ng-controller="{{component.controller}}">
<i class="{{component.icon}}"><br></i>
{{component.name}}
</a>
In the case ng-click="{{component.ngclick}}" und ng-controller="{{component.controller}}" will not be included.
At the appropriate places I get from my editor WebStorm following error: Identifier or String literal or numeric literal expected.
I have a {{expression}} Problem. How can I integrate the ng-controller and ng-click as a string from a json object?
This is quite tricky. Angular team on their doc suggests that controller should be registered to a module while the DOM is being parsed.
All the $scope properties will be available to the template at the point in the DOM where the Controller is registered.
Link: Angular controllers
Use $controllerProvider to register the controller This link
shed's some light on how controllers are resolved at later point of
the time, which might help you in designing your code as desired.
ng-click you can give an expression or a method which is inside the controller of $scope tree. Both the expression and/or function
search happens inside the $scope tree at the compile time of your
template.
Update As per the fiddler requested
I have corrected the fiddler code, removed unwanted lines, errors and made it working.
Now your template is dynamic binding to the JavaScript code at the run-time.
Fiddler Link
Javascript:
var myApp = angular.module('starter', []);
myApp.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://api.myjson.com/**'
]);
}]);
myApp.controller('generateHTMLCtrl', function ($scope, $http, $compile, $interpolate, $templateCache) {
$http.get('https://api.myjson.com/bins/1gkh0').success(function (data) {
for(var i in data){
var interpolated = $interpolate($templateCache.get("tpl").trim())(data[i]);
angular.element(document.querySelector("#loadhere")).append($compile(interpolated)($scope));
}
});
});
myApp.controller("OpenLinkCtrl", function ($scope) {
$scope.OpenLink = function () {
alert("Link open");
}
});
Html:
<body ng-app="starter" class="padding" style="text-align: center">
<div class="row responsive-md" ng-controller="generateHTMLCtrl" id="loadhere"></div>
<script type="text/ng-template" id="tpl">
<div class="col">
<a style="color:{{color}}; background-color:{{backgroundcolor}} "
id="{{id}}" class="{{type}}" href="{{topage}}" ng-controller="{{controller}}" ng-click="{{function}}"><i class="{{icon}}"><br></i>{{name}}</a>
</div>
</script>
</body>
Explanation:
Used interpolate service
Used compiler service
Note: Interpolator cannot parse on array of objects. Hence used for loop to interpolate each oject array and append it to the DOM.
More info on compiler and interpolation can be found here
I'm not sure that it's possible the ng-controller could be a {{ expression }}.
The workarround it's creating a function that returns the name of the controller that you want and you can assign to a var inside the controller...
In other case, why you want to use a different controller for each button?

Can't populate data with binding

This is my first try to make a single page application with HTML5. I'm using jquery, knockout and sammy.
Code: http://codepaste.net/apdrme
The problem is that I don't know what I'm doing wrong. I know it is the following:
this.get("#/", function() {
this.personList(this.persons);
});
But how else can I populate the list?
You could populate your list as follows:
function ViewModel() {
this.personList = ko.observableArray([{"name":"Josh"}, {"name":"Barry"}, {"name":"Mike"}]);
};
[...]
ko.applyBindings(new ViewModel());
Pay attention to use ko.observableArray() at the declaration. So, you could also remove the argument and call this.personList([{"name":"Josh"}, {"name":"Barry"}, {"name":"Mike"}]) in your main Sammy route and fill the list with other values in another route.
Another mistake is that you have used the with-binding that is not necessary here. Check the documentation about it.
You would normally use jQuery and an ajax call to populate personList. personList should be an ko.observableArray.
this.personList = ko.observableArray();
this.get("#/", function() {
$.ajax({url:"/api/persons/", dataType: 'json', success:function(persons){
this.personList(persons);
}});
});

parse dojoAttachEvent in content returned from xhr in a custom widget?

Instead of the typical custom widget that mixes in _Templated for it's markup, I want a widget that just mixes in _Widget then does an xhrGet to fetch the markup. In addition, and this is the part that I need help with, I want dojo to parse the xhr result text for dojoAttachPoint and dojoAttachEvent in the context of the widget, hookup up nodes and events.
The core of what I've tried for the widget is below:
dojo.provide("com.example.widget.DynamicAttachedTemplate");
dojo.require("dijit._Widget");
dojo.require("dojo.html");
dojo.declare("com.example.widget.DynamicAttachedTemplate", [dijit._Widget], {
postCreate: function() {
dojo.xhrGet({
url: "/product/ajax/editTemplate",
content: { id: 1 },
handleAs: "text",
preventCache: true,
load: dojo.hitch(this, function(markup) {
// this only parses markup for dojoType it seems :(
dojo.html.set(this.srcNodeRef, markup, { parseContent: true });
},
error: function(error) {
alert(error);
}
});
},
submitHandler: function(event) {
dojo.stopEvent(event);
// handle validation, form submit, etc.
}
});
And the page that uses it could look something like this:
...
<div id="productEditContainer">
loading...
</div>
...
<script type="text/javascript">
dojo.addOnLoad(function() {
dojo.require("com.example.widget.DynamicAttachedTemplate");
new com.example.widget.DynamicAttachedTemplate({}, dojo.byId("productEditContainer"));
});
</script>
And let's say the markup returned from /product/ajax/editTemplate?id=1 was something like:
<form dojoAttachEvent="onsubmit: submitHandler">
...
</form>
In the end I want the dojoAttachEvent="onsubmit: submitHandler" in the xhr returned template markup to result in an event connect from the form submit to the widget submit handler method. I'm open to better approaches as well but the widget markup needs to be generated on the server and I'd really like to leverage dojoAttach* instead of using DOM IDs and manually hooking things up via dojo.byId in the widget setup code.
consider using inline template: http://www.sitepen.com/blog/2008/06/24/creating-dojo-widgets-with-inline-templates/.
However it requires _Templated.