Data context on JsViews' include tag - javascript

I made a snippet to show the issue I'm facing:
<html>
<head>
<title>Demo 1 JsViews</title>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
</head>
<body>
<script id="template" type="text/x-jsrender">
<p>{{:property}}</p>
{^{on ~root.testFunction}}PUSH ME!{{/on}}
{{for nestedObjects}}
{{include #data tmpl="#template-2"/}}
{{/for}}
</script>
<div id="container"></div>
<script id="template-2" type="text/x-jsrender">
<p>{{:~root.property}}</p>
{^{on ~root.testFunction}}PUSH ME!{{/on}}
</script>
<div id="container-2"></div>
<script>
data = {
property : "PARENT",
testFunction : function(){ alert(this.property); },
nestedObjects : [
{
id: 0,
property: "CHILD1",
testFunction : function(){ alert(this.property);}
},
{
id: 1,
property: "CHILD2",
testFunction : function(){ alert(this.property);}
}]
};
/**
* Funciones
*/
$(document).ready(function(){
var tmpl = $.templates("#template");
tmpl.link("#container", data);
});
</script>
</body>
</html>
As you can see, in '#template-2' it's taking the properties from main data object, not from each nestedObjects' item. I know this would be the normal behaviour.
Is there a way to make include tag to take each nestedObjects' item and not the whole data object as context?
I know that if I remove the '~root' modifiers in '#template-2' it will work as expected, but I need it to work with '~root' modififer if possible.
Thanks in advance :)

After trying many things, I managed to get it working in another way using a helper object, if someone has a similar issue feel free to contact me :).

~root is a built-in helper that points to the top-level data that you passed to the link() or render() method. See
http://www.jsviews.com/#contextualparams#root.
So you can't change it to have it point somewhere else. But you can create your own helpers (not using the reserved root name), such as:
{{include #data ~myroot=#data tmpl="#template-2"/}}
and in template-2 write
{{:~myroot.property}}

Related

SAPUI5 Select first item in list after rendering

I have a Master-Detail application and I would like the first list item to be selected automatically once the application is loaded. I have tried the following solution but it does not work:
onAfterRendering: function() {
var oList = this.getView().byId("bankList");
var aItems = oList.getItems("listItems");
console.log(aItems);
if (aItems.length) {
aItems[0].setSelected(true);
}
}
The strange thing is that aItems seems to be empty even though it contains the correct details. Below is what is printed in the console when I console.log(aItems):
The result of console.log(aItems)
Guessing that you are using a sap.m.List, You should use the setSelectedItem() function, that receives the Item object as parameter.
Furthermore I recommend you to avoid using the onAfterRendering lifecycle method, to keep the lifecycle clean. There are usually many items that you can use, for example updateFinished for sap.m.List
Here the snippet
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<meta charset="utf-8">
<title>MVC with XmlView</title>
<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
<script id='sap-ui-bootstrap' src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js' data-sap-ui-theme='sap_belize_plus' data-sap-ui-libs='sap.m' data-sap-ui-xx-bindingSyntax='complex'></script>
<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->
<!-- define a new (simple) View type as an XmlView
- using data binding for the Button text
- binding a controller method to the Button's "press" event
- also mixing in some plain HTML
note: typically this would be a standalone file -->
<script id="view1" type="sapui5/xmlview">
<mvc:View xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
<List items="{/options}" mode="SingleSelect" updateFinished="onUpdateFinished">
<StandardListItem title="{value}"></StandardListItem>
</List>
</mvc:View>
</script>
<script>
// define a new (simple) Controller type
sap.ui.controller("my.own.controller", {
onUpdateFinished: function(oEvent) {
var oList = oEvent.getSource();
var aItems = oList.getItems();
oList.setSelectedItem(aItems[0])
}
});
/*** THIS IS THE "APPLICATION" CODE ***/
// create some dummy JSON data
var data = {
options: [{
key: '1',
value: 'option 1'
}, {
key: '2',
value: 'option 2'
}, {
key: '3',
value: 'option 3'
}]
};
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData(data);
// instantiate the View
var myView = sap.ui.xmlview({
viewContent: jQuery('#view1').html()
}); // accessing the HTML inside the script tag above
myView.setModel(oJSONModel);
// put the View onto the screen
myView.placeAt('content');
</script>
</head>
<body id='content' class='sapUiBody'>
</body>
</html>

Use the same data object across multiple templates in Handlebars.js

I want to use the same data object across multiple templates in different contexts, how can I reuse it. By any chance, handlebars partials would be helpful in this situation.
$("document").ready(function(){
var source = $("#homePage-template").html();
var template = Handlebars.compile(source);
var dataPanel = {activites:[
{activity: "Events" , activityRedirect:"#", icon:"fa fa-camera-retro" , imageUrl:"xyz"},
{activity: "Ciriculars" , activityRedirect:"#", icon:"fa fa-paper-plane", imageUrl:"xyz"}
]};
$("#homePage-placeholder").html(template(dataPanel));
$("#another-placeholder").html(template(dataPanel));
});
And here is my template:
<script id="homePage-template" type="text/x-handlebars-template">
<ul>
{{#activites}}
<li><i class="{{icon}}" aria-hidden="true"></i>{{activity}}</li>
{{/activites}}
</ul>
</script>
Another Template
<script id="another-template" type="text/x-handlebars-template">
{{#activites}}
<div>
<img src="{{imageUrl}}"/>
<span>{{activity}}</span>
</div>
{{/activites}}
</script>
Now how can I reuse this data into "another-template", because I want an image and text in that but it renders like "homePage-template" only in form of a list, if anyone has an idea over this!
In order to have a second template you must fetch its HTML source from the DOM and compile it into a template method just as you are doing for the Home Page Template.
var homepage_template_source = $('#homePage-template').html();
var another_template_source = $('#another-template').html();
var homepage_template = Handlebars.compile(homepage_template_source);
var another_template = Handlebars.compile(another_template_source);
You must call the template method for the specific template you wish to render:
$("#homePage-placeholder").html(homepage_template(dataPanel));
$("#another-placeholder").html(another_template(dataPanel));
See this fiddle for an example.

JQuery and Autocomplete Using a List (Python/Flask)

This has probably been asked before, but after searching for awhile I'm still a bit confused. I'm trying to make a flask app but I'm not too familiar with JQuery itself, but I would like to create an autocomplete widget in my html. However, instead of querying a database I'd like to just use a static list and a regex to get results. I used this as reference.
What I did was:
#app.route('/autocomplete', methods=['GET'])
def autocomplete():
search = request.args.get('q')
#query = db_session.query(Movie.title).filter(Movie.title.like('%' + str(search) + '%'))
#results = [mv[0] for mv in query.all()]
results = ['Beer', 'Wine', 'Soda', 'Juice', 'Water']
return jsonify(matching_results=results)
while keeping the rest of the code:
<head>
<link href="//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" rel="Stylesheet"></link>
<script src="//code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="//code.jquery.com/ui/1.10.2/jquery-ui.js" ></script>
<script type="text/javascript">
$(function() {
$("#autocomplete").autocomplete({
source:function(request, response) {
$.getJSON("{{url_for('autocomplete')}}",{
q: request.term, // in flask, "q" will be the argument to look for using request.args
}, function(data) {
response(data.matching_results); // matching_results from jsonify
});
},
minLength: 2,
select: function(event, ui) {
console.log(ui.item.value); // not in your question, but might help later
}
});
})
</script>
</head>
<body>
<div>
<input name="autocomplete" type="text" id="autocomplete" class="form-control input-lg"/>
</div>
</body>
I haven't implemented a regex but I assumed if I typed anything with at least 2 characters I would get a dropdown of the list I wrote above. However, I get nothing. Any ideas on how I can get this autocomplete to work?

Knockout did not render template with my data

Stuck with javascipt's knockout library.
So, I want to implement simple forum. I have javascript file with two ajax requests, for topics and for posts. And I have html template.
function dealModel() {
var self = this;
self.board = ko.observableArray([]);
var res = [];
$.getJSON("http://someaddress/threads", function(data) {
$.each(data, function(i, thread) {
var js = jQuery.parseJSON(thread);
js.posts = ko.observableArray([]);
var postres = []
$.getJSON("http://someadress/posts/" + js.id, function(postdata) {
$.each(postdata, function(idx, post){
var jspost = jQuery.parseJSON(post);
postres.push(jspost);
})
})
js.posts(postres);
res.push(js);
})
self.board(res);
})
}
$(document).ready(function(){
ko.applyBindings(new dealModel());
});
var testdata = [{text : "text 1"} , {text : "text2"}]
This is my js code. It perfectly works with topics, but when I put my posts, my observable array "posts" already empty.
For test I created test array "testdata" (below), and pass in my observable array. And, javascript work perfectly.
Here is my template
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
<script type="text/javascript" src="ajaxknockout.js"></script>
</head>
<body>
<div class='board'>
<div class='threads' data-bind="foreach: board">
<p data-bind="text: title"></p>
<div class= "posts" data-bind="foreach: $data.posts">
<p data-bind="text: text"> </p>
</div>
</div>
</div>
</body>>
</html>
So, I think something bad with my posts JSON.
Here it is.
["{\"createTime\": \"Monday, 04. January 2016 05:53PM\",\"thread_id\": \"2\",\"text\": \"post 1\",\"id\": \"4\"}", "{\"createTime\": \"Monday, 04. January 2016 05:53PM\",\"thread_id\": \"2\",\"text\": \"post 2\",\"id\": \"5\"}", "{\"createTime\": \"Monday, 04. January 2016 05:53PM\",\"thread_id\": \"2\",\"text\": \"post 3\",\"id\": \"6\"}"]
SO, I have a question. Whats wrong with my code? Why knockout understand my testdata, but completly reject production data?
That's because this part of your first json request:
js.posts(postres);
executes ahead of callback from your second json request where you are pulling posts. You have to change that so the posts array is populated before doing js.posts(postres);, e.g like so:
$.getJSON("http://someadress/posts/" + js.id, function(postdata) {
$.each(postdata, function(idx, post){
var jspost = jQuery.parseJSON(post);
postres.push(jspost);
})
js.posts(postres);
})

Rendering one mustache partial multiple times with different data

I have two objects that I want to render side by side. There is never a case where I will want to render more, or less than two. My model is setup like so:
{
obj1: {...},
obj2: {...}
}
Using mustache templates, I want to render each object using the same partial:
<div>
<h1>Object 1</h1>
{{>objPartial}}
</div>
<div>
<h1>Object 2</h1>
{{>objPartial}}
</div>
However, mustache doesn't seem to support passing a context to the partial. Doing something like {{>objPartial obj1}} seems like it should be supported, but I can't find any documentation on setting a context for a partial.
Is this sort of thing supported? If not, how can I accomplish the same effect without duplicating the partial (objPartial1 and objPartial2)?
The syntax I think you are looking for is not {{>objPartial obj1}}, but rather it should be
{{#obj1}}
{{>objPartial}}
{{/obj1}}
The syntax for {{#}} isn't only for arrays - for non array objects the object becomes part of the current scope.
I've forked maxbeatty's example and modified it to show this syntax:
<script type="template/text" id="partial">
<ul>
{{#name}}
<li>{{.}}</li>
{{/name}}
</ul>
</script>
<script type="template/text" id="main">
<div>
<h1>Stooges</h1>
{{#object1}}
{{>objPartial}}
{{/object1}}
</div>
<div>
<h1>Musketeers</h1>
{{#object2}}
{{>objPartial}}
{{/object2}}
</div>
</script>​
<script type="text/javascript">
var partial = $('#partial').html(),
main = $('#main').html(),
data = {
object1: {
name: ["Curly", "Moe", "Larry"]},
object2: {
name: ["Athos", "Porthos", "Aramis", "D'Artagnan"]}
},
html = Mustache.to_html(main,data, {
"objPartial": partial
});
document.write(html);
</script>
Link to jsfiddle: http://jsfiddle.net/YW5zF/3/
You could adjust your model to include the h1 and div so you could loop over a list sending different data to objPartial each time
<script type="template/text" id="partial">
<ul>
{{#name}}
<li>{{.}}</li>
{{/name}}
</ul>
</script>
<script type="template/text" id="main">
{{#section}}
<div>
<h1>{{title}}</h1>
{{>objPartial}}
</div>
{{/section}}
</script>
<script type="text/javascript">
var partial = $('#partial').html(),
main = $('#main').html(),
data = {
section: [
{
title: "Object 1",
name: ["Curly", "Moe", "Larry"]},
{
title: "Object 2",
name: ["Athos", "Porthos", "Aramis", "D'Artagnan"]}
]
},
html = Mustache.to_html(main,data, {
"objPartial": partial
});
document.write(html);
</script>
See it on jsFiddle

Categories