Create dynamic pages from Json, in Dojo - javascript

I have a json file
{
Introduction:
[
{
title: "Introduction",
toolbar: "Page 1",
content: "cont, aabitant morbi tristique..."
},
{
title: "about",
toolbar: "Page 2",
content: "contesent vel nisi ipsum..."
},
{
title: "services",
toolbar: "Page 3",
content: "Cras adipiscing sapien nec..."
}
]
}
I want to create dynamic pages in Dojo mobile. From the above Json three pages will be created with moving back and forward. I am getting problems. I am reading Json as:
dojo.xhrPost({
url: "start.json",
handleAs: "json",
var viewContainer = new dojox.mobile.ScrollableView({id:"viewContainer"});
load: function(response) {
for (key in response){
// creating each view heading and content here.........
//can you give some hint what should be here?
}
}
How can I read above json and create dynamic views. What could be replace with this line in code //can you give some hint what should be here?

First, you're reading json in the wrong way.
dojo.xhrPost will send data to the url you specify in the url parameter : not retrieve the file in the url parameter. If you do it the way you're doing, you'll end up with an error such as "Unable to load start.json status:500"
So, in your case, to read the file, you should do a dojo.xhrGet instead.
Next, your viewContainer variable should not be placed like that, in the middle of the arguments (you are writing code mixed in the middle of object properties (!!!)).
So... you should be able to accomplish what you want by doing something like this :
require(["dojo/dom-construct",
"dojo/_base/xhr",
"dojox/mobile/parser",
"dojox/mobile",
"dojox/mobile/ScrollableView",
"dojox/mobile/Heading"],
function(domConstruct) {
dojo.xhrGet({
url : 'start.json',
handleAs : "json",
load : function(response) {
dojo.forEach(response.Introduction, function(page){
var node = domConstruct.create("div", {id : page.title}, "viewsContainer", "last");
var view = new dojox.mobile.ScrollableView({
id : page.title
}, node);
view.addChild(new dojox.mobile.Heading({label : page.title}));
view.startup();
});
},
error : function(err) {
console.debug("Error : ", err);
}
});
}
);

load: function(response) {
for (key in response.Introduction){
// creating each view heading and content here.........
}
and try to debug data for key it should be any object that you pass 3 obj in json...

here each key has three property that you define in json,now u can inject values to html view
by accessing property like this key.title,key.toolbar....,ex:- $('<p>' + key.title + '</p>');

Related

Using ajax call to generate array for link_list for tinymce

I'm trying to create a link_list in TinyMCE (version 6) using an AJAX call (not sure if this is the right way, but I'm trying to update old code). The backend is handled with Flask, which gets a tuple of dictionaries from the database where the title and value of each link are key-value pairs. I believe what I need to do is find a way to make the ajax call return the correct type of array, e.g.
my_ary=[
{ title: 'title 1',value: 'link1'},
{ title: 'title 2',value: 'link2'},
{ title: 'title 3',value: 'link3'},
]
Is this possible? Or am I heading in a completely incorrect direction? This is what I currently have-
tinyMCE intialization:
tinymce.init({
selector: '.my_editor',
plugins: ['link'],
toolbar: 'link',
link_list: (success) => {
const links = update_item_list();
success(links);
},
});
javascript containing ajax call:
function update_item_list()
{
my_link_list = $.ajax({
async: false,
type: "POST",
url: "ajax_endpoint",
data: {},
cache: false,
dataType: "json",
success: function(list)
{
const my_ary=Array.from(Array(list.length), () => ({ title: '', value: '' }))
for(var i = 0; i < list.length; i++)
{
my_ary[i].title=list[i].title;
my_ary[i].value=list[i].value;
}
},
error: function(html, status)
{
alert("error: " + status);
}
});
return my_link_list;
}
flask endpoint:
#my_project.route('/ajax_endpoint',methods=['POST'])
def ajax_endpoint():
uploaded_items = ["{" + ", ".join([f"""'{key}': '{item.get(key)}'""" for key in item.keys()]) + "}" for item in get_link_items()]
html = "[" + ", ".join(uploaded_items) + "]"
return jsonify(html)
I figured out a solution without using ajax. Per tinyMCE's documentation for link_list, one can use a URL which returns JSON data. To accomplish this, I created a list of dictionaries with keys of "title" and "value" for each link, and then used jsonify when returning the list. Now, this is what my code looks like-
tinyMCE intialization:
tinymce.init({
selector: '.my_editor',
plugins: ['link'],
toolbar: 'link',
link_list: "ajax_endpoint"
},
});
flask endpoint:
#my_project.route('/ajax_endpoint',methods=['POST'])
def ajax_endpoint():
html = [{"title": item.get('title'), "value": item.get('value')} for item in get_link_items()]
return jsonify(html)

Connecting dojo dgrid to solr

I'm trying to connect a dojo dgrid to a solr data service and need some help.
When I use jsonp I can get connected to the solr data and output the data result to the screen with something like this:
dojo.require("dojo.io.script");
function searchGoogle(){
// Look up the node we'll stick the text under.
var targetNode = dojo.byId("output");
// The parameters to pass to xhrGet, the url, how to handle it, and the callbacks.
var jsonpArgs = {
url: "myExternalSolrURL",
callbackParamName: "json.wrf",
content: {
wt: "json",
rows: "12",
start: "1",
q: "*"
},
load: function(data){
// Set the data from the search into the viewbox in nicely formatted JSON
targetNode.innerHTML = "<pre>" + dojo.toJson(data, true) + "</pre>";
},
error: function(error){
targetNode.innerHTML = "An unexpected error occurred: " + error;
}
};
dojo.io.script.get(jsonpArgs);
}
dojo.ready(searchGoogle);
But, when I try to use jsonrest to connect to the solr data and get it to show up in a dgrid nothing appears to happen. This is the code I have for that:
<script>
var myStore, dataStore, grid;
require([
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dgrid/Grid",
"dojo/data/ObjectStore",
"dojo/query",
"dijit/form/Button",
"dojo/domReady!"
], function (JsonRest, Memory, Cache, Grid, ObjectStore, query, Button, domReady) {
myStore = Cache(JsonRest({
target: "myExternalSolrURL",
idProperty: "id"
}),
Memory({ idProperty: "id" }));
grid = new Grid({
store: dataStore = ObjectStore({ objectStore: myStore }),
structure: [
{ name: "Thing id", field: "id", width: "50px" },
{ name: "Name", field: "name", width: "200px" },
{ name: "detail", field: "detail", width: "200px" }
]
}, "grid"); // make sure you have a target HTML element with this id
grid.startup();
});
</script>
<div style="height: 300px; width: 600px; margin: 10px;">
<div id="grid">
</div>
</div>
Does anyone see what I am missing?
You changed your code to use dgrid, but it looks like you are still attempting to use a dojo/data store with dgrid. dgrid only supports the dojo/store API, so stop wrapping your store in ObjectStore.
dgrid/List and dgrid/Grid do not contain store logic. You will want to either use dgrid/OnDemandGrid or mix in dgrid/extensions/Pagination.
Make sure the service you are using with dojo/store/JsonRest actually behaves as the store implementation expects (or use or write a diffrent dojo/store implementation)
Apparently part of the problem is that a Solr index is not a flat data structure like a grid or dgrid can deal with. When you have nested data returned like a Solr or ElasticSearch index will return it must be "flattened" to go into a grid. However, this sort of hierarchy of data will work with a tree vs a grid. So the next challenge is to connect to the index and flatten it.

Facebook Feed - JS SDK

I am trying to create a user's feed on my page using Facebook JS SDK but I am having issues accessing the values of nested objects.
This is my code:
FB.api('/me/feed', function(response) {
alert(response.data);
});
The alert here will return [object Object]
The data object is this:
{
"data": [
{
"message": "Some message",
"id": "some ID",
"created_time": "2014-01-05T22:46:10+0000"
}
],
"paging": {
"previous": "Link",
"next": "Link"
}
}
I need to access the message part of the object but I don't know how.
Simply access the properties directly
FB.api('/me/feed', function(response) {
alert(response.data.message);
});
I had to use JSON after all
FB.api('/me/feed',{limit:10}, function(response){
var jsonText = JSON.stringify(response.data,["picture"]);
alert(jsonText);
});
This will return an array with all the values of 'picture'
This is the example output
[{"picture":"https://fbcdn-photos-d-a.akamaihd.net"},
{"picture":"https://fbcdn-photos-g-a.akamaihd.net"},
{"picture":"https://fbexternal-a.akamaihd.net"},{},
{"picture":"https://fbcdn-profile-a.akamaihd.net"}]
It looks likedata is an array with a single element, so to get message, you will want to use response.data[0].message

twitter bootstrap typeahead (method 'toLowerCase' of undefined)

I am trying to use twitter bootstrap to get the manufacturers from my DB.
Because twitter bootstrap typeahead does not support ajax calls I am using this fork:
https://gist.github.com/1866577
In that page there is this comment that mentions how to do exactly what I want to do. The problem is when I run my code I keep on getting:
Uncaught TypeError: Cannot call method 'toLowerCase' of undefined
I googled around and came tried changing my jquery file to both using the minified and non minified as well as the one hosted on google code and I kept getting the same error.
My code currently is as follows:
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
var manufacturers = new Array;
$.map(results.data.manufacturers, function(data, item){
var group;
group = {
manufacturer_id: data.Manufacturer.id,
manufacturer: data.Manufacturer.manufacturer
};
manufacturers.push(group);
});
typeahead.process(manufacturers);
}
});
},
property: 'name',
items:11,
onselect: function (obj) {
}
});
on the url field I added the
window.location.origin
to avoid any problems as already discussed on another question
Also before I was using $.each() and then decided to use $.map() as recomended Tomislav Markovski in a similar question
Anyone has any idea why I keep getting this problem?!
Thank you
Typeahead expect a list of string as source
$('#manufacturer').typeahead({
source : ["item 1", "item 2", "item 3", "item 4"]
})
In your case you want to use it with a list of objects. This way you'll have to make some changes to make it works
This should works :
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
var manufacturers = new Array;
$.map(results.data.manufacturers, function(data){
var group;
group = {
manufacturer_id: data.Manufacturer.id,
manufacturer: data.Manufacturer.manufacturer,
toString: function () {
return JSON.stringify(this);
},
toLowerCase: function () {
return this.manufacturer.toLowerCase();
},
indexOf: function (string) {
return String.prototype.indexOf.apply(this.manufacturer, arguments);
},
replace: function (string) {
return String.prototype.replace.apply(this.manufacturer, arguments);
}
};
manufacturers.push(group);
});
typeahead.process(manufacturers);
}
});
},
property: 'manufacturer',
items:11,
onselect: function (obj) {
var obj = JSON.parse(obj);
// You still can use the manufacturer_id here
console.log(obj.manufacturer_id);
return obj.manufacturer;
}
});
In my case, I was getting this exact error, and it turned out that the version of Bootstrap I was using (2.0.4) did not support passing in a function to the source setting.
Upgrading to Bootstrap 2.1.1 fixed the problem.
UPDATED / REVISED LOOK AT THE ISSUE: The error you mentioned "Cannot call method 'toLowerCase' of undefined" occurred to me when I used the original Typeahead extension in bootstrap that does not support AJAX. (as you have found) Are you sure that the original typeahead extension isn't loading, instead of your revised one?
I have been sucessfully using this Gist of typeahead that is a slight variation on the one you mention. Once I switched to that Gist and confirmed that the input data was good (testing that the input was a string array in an JS object, the issue went away.
Hope this helps
Original answer:
The reason the error occurs is because the value passed into the typeahead matcher function is undefined. That is just a side effect to the real issue which occurs somewhere between your input and that matcher function. I suspect the 'manufacturers' array has a problem. Test it first to verify you have a valid array.
// It appears your array constructor is missing ()
// try the following in your binding code:
var manufacturers = new Array();
Here is what I am using to bind the input to typeahead. I confirmed that it works with your modified typeahead fork.
My HTML:
<!-- Load bootstrap styles -->
<link href="bootstrap.css" rel="stylesheet" type="text/css" />
...
<input type="text" class="typeahead" name="Category" id="Category" maxlength="100" value="" />
...
<!-- and load jQuery and bootstrap with modified typeahead AJAX code -->
<script src="jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="bootstrap-modified-typeahead.js" type="text/javascript"></script>
My binding JavaScript code:
// Matches the desired text input ID in the HTML
var $TypeaheadInput = $("#Category");
// Modify this path to your JSON source URL
// this source should return a JSON string array like the following:
// string[] result = {"test", "test2", "test3", "test4"}
var JsonProviderUrl = "../CategorySearch";
// Bind the input to the typeahead extension
$TypeaheadInput.typeahead({
source: function (typeahead, query) {
return $.post(JsonProviderUrl, { query: query }, function (data) {
return typeahead.process(data);
});
}
});
In my case I had null values in my source array causing this error.
Contrived example:
source : ["item 1", "item 2", null, "item 4"]
Your manufacturer objects don't have a "name" property, you should change
property: 'name',
to
property: 'manufacturer',
Have you tried using mapping variables like example below, you need to use this when you got more then one property in your object;
source: function (query, process) {
states = [];
map = {};
var data = [
{"stateCode": "CA", "stateName": "California"},
{"stateCode": "AZ", "stateName": "Arizona"},
{"stateCode": "NY", "stateName": "New York"},
{"stateCode": "NV", "stateName": "Nevada"},
{"stateCode": "OH", "stateName": "Ohio"}
];
$.each(data, function (i, state) {
map[state.stateName] = state;
states.push(state.stateName);
});
process(states);
}
I stumbled upon this issue a while ago. I advice you to recheck configuration where you are including typeahead libraries (via main.js, app.js or config.js).
Otherwise, you can overwrite the latest Bootstrap version to your application library.
Try this code:
String.prototype.hashCode = function(){
var hash = 0;
if (this.length == 0) return hash;
for (i = 0; i < this.length; i++) {
char = this.charCodeAt(i);
hash = ((hash<<5)-hash)+char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
var map_manufacter, result_manufacters;
$('#manufacturer').typeahead({
source: function(typeahead, query){
$.ajax({
url: window.location.origin+"/bows/get_manufacturers.json",
type: "POST",
data: "",
dataType: "JSON",
async: false,
success: function(results){
result_manufacter = [], map_manufacters = {};
$.each(results.data.manufacturers, function(item, data){
map_manufacters[data.Manufacturer.manufacturer.hashCode()] = data;
result_manufacters.push(data.Manufacter.manufacter);
});
typeahead.process(result_manufacters);
}
});
},
property: 'name',
items:11,
onselect: function (obj) {
var hc = obj.hashCode();
console.log(map_manufacter[hc]);
}
});
I solved this problem only updating the file bootstrap3-typeahead.min.js to the file in https://github.com/bassjobsen/Bootstrap-3-Typeahead/blob/master/bootstrap3-typeahead.min.js
I think most people can solve this way.

Load data into a Backbone collection from JSON file?

I'm trying to load some data into a Backbone Collection from a local JSON file, using this very basic code:
window.Student = Backbone.Model.extend({
});
window.Students = Backbone.Collection.extend({
model: Student,
});
window.AllStudents = new Students();
AllStudents.fetch({ url: "/init.json"});
console.log('AllStudents', AllStudents);
In the console statement, AllStudents is empty. But init.json is definitely being loaded. It looks like this:
[
{ text: "Amy", grade: 5 },
{ text: "Angeline", grade: 26 },
{ text: "Anna", grade: 55 }
]
What am I doing wrong?
UPDATE: I've also tried adding a reset listener above the .fetch() call, but that's not firing either:
AllStudents.bind("reset", function() {
alert('hello world');
});
AllStudents.fetch({ url: "/init.json"});
No alert appears.
UPDATE 2: Trying this script (reproduced here in full):
$(function(){
window.Student = Backbone.Model.extend({
});
window.Students = Backbone.Collection.extend({
model: Student,
});
window.AllStudents = new Students();
AllStudents.url = "/init.json";
AllStudents.bind('reset', function() {
console.log('hello world');
});
AllStudents.fetch();
AllStudents.fetch({ url: "/init.json", success: function() {
console.log(AllStudents);
}});
AllStudents.fetch({ url: "/init.json" }).complete(function() {
console.log(AllStudents);
});
});
Only one console statement even appears, in the third fetch() call, and it's an empty object.
I'm now absolutely baffled. What am I doing wrong?
The JSON file is being served as application/json, so it's nothing to do with that.
The attribute names and non-numeric attribute values in your JSON file must be double quoted (" ") . Single quotes or no-quotes produces errors and response object is not created that could be used to create the models and populate the collection.
So. If you change the json file content to :
[
{ "text": "Amy", grade: 5 },
{ "text": "Angeline", grade: 26 },
{ "text": "Anna", grade: 55 }
]
you should see the non-empty collection object.
You can change your code to see both success and failure as below:
AllStudents.fetch({
url: "/init.json",
success: function() {
console.log("JSON file load was successful", AllStudents);
},
error: function(){
console.log('There was some error in loading and processing the JSON file');
}
});
For more details, probably it will be a good idea to look in to the way ajax response objects are created.
I/O operations in javascript are almost always asynchronous, and so it is with Backbone as well. That means that just because AllStudents.fetch has returned, it hasn't fetched the data yet. So when you hit your console.log statement, the resources has not yet been fetched. You should pass a callback to fetch:
AllStudents.fetch({ url: "/init.json", success: function() {
console.log(AllStudents);
}});
Or optionally, use the new promise feature in jQuery (fetch will return a promise):
AllStudents.fetch({ url: "/init.json" }).complete(function() {
console.log(AllStudents);
});
fetch() returns a 'success' notification as already stated, but that just means that the server request was successful. fetch() brought back some JSON, but it still needs to stuff it into the collection.
The collection fires a 'reset' event when it's contents have been updated. That is when the collection is ready to use...
AllStudents.bind('reset', function () { alert('AllStudents bind event fired.'); });
It looks like you had this in your first update. The only thing I did differently was to put fetch() in front of the event binding.
I think you need to add {add:true} to the options of fetch,
if you assigned the fetch to a variable, you would get the result as well,
but then its not inside the collection you wanted

Categories

Resources