I created a custom control and created two objects of it in sapui5. in my customControl.js in onAfterRendering function I wrote a setInterval code which will update the value property of custom control periodically. I create my custom controls in my view :
<controls:customControl
id="customID1"
value="50"/>
<controls:customControl
id="customID2"
value="70"/>
Here is my control :
CustomControl.prototype.onAfterRendering = function()
{
setInterval(this.updateControl(this), 500);
}
But it seems when this method works, it updates all custom control objects with same value. So when I update the value property of first control as 52 and the value property of second control as 72. But I only can see 72 value for both controls.
I also tried to use sap.ui.core.IntervalTrigger method in my onAftering method like below:
var iT = new sap.ui.core.IntervalTrigger(500);
iT.addListener(this.updateControl, this);
but this doesn't work and I last tried to use closure but it doesn't work again.
(function(self){
var iT = new sap.ui.core.IntervalTrigger(500);
iT.addListener(self.updateGauge, self);
})(this);
#melomg, you should post some more details, including you custom control and the implementation of your updateControl function. I can only guess what's going wrong, anyway... Here is a working example (see code below) which runs just fine. Check the comments in the code for more information, especially because of the re-rendering loop issue that you might have (I can only guess this).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SAPUI5 single file template | nabisoft</title>
<script src="https://openui5beta.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.m"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"></script>
<!-- XMLView -->
<script id="myXmlView" type="ui5/xmlview">
<mvc:View
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns:nabisoft="nabisoft">
<!-- use our custom control, see below -->
<nabisoft:CustomControl id="one" value="1" interval="500"/>
<nabisoft:CustomControl id="two" value="90000" interval="1000"/>
</mvc:View>
</script>
<script>
sap.ui.getCore().attachInit(function () {
"use strict";
//### Custom Control ###
jQuery.sap.declare("nabisoft.CustomControl");
sap.ui.core.Control.extend("nabisoft.CustomControl", {
metadata : {
properties : {
value : {type : "int"},
interval : {type : "int", default:500}
},
aggregations : {},
associations: {},
events : {}
},
init : function(){},
onAfterRendering: function (){
setInterval(this.updateControl.bind(this), this.getInterval());
},
updateControl : function () {
var iOldValue = this.getValue();
var iNewValue = iOldValue + 1;
// don't do this, because this will lead to a rerendering loop!!!
//this.setValue( iNewValue );
//instead do this here:
this.setProperty("value", iNewValue, true /*supress rerendering*/);
this.$().find("span").text(iNewValue);
},
renderer : {
render : function(oRm, oControl) {
oRm.write("<div");
oRm.writeControlData(oControl);
oRm.addClass("nsCustomControl");
oRm.writeClasses();
oRm.write(">");
oRm.write("<div>" + oControl.getId() +" : <span>" + oControl.getValue() + "</span></div>");
oRm.write("</div>");
}
}
});
//### THE APP: place the XMLView somewhere into DOM ###
sap.ui.xmlview({
viewContent : jQuery("#myXmlView").html()
}).placeAt("content");
});
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>
Related
I've been trying to get my first Backbone.js app up and running, following the Backbone.js primer here.
I've followed the example through and now I'm trying to customise it for my purposes which are to simply retrieve and read a JSON file from my server. I don't need to be able to change or delete any of the data.
I've set up my html as per the primer below:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Backbone.js Primer</title>
<script type="text/javascript" src="./node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./node_modules/underscore/underscore-min.js"></script>
<script type="text/javascript" src="./node_modules/backbone/backbone-min.js"></script>
<script type="text/javascript" src="./node_modules/moment/moment.js"></script>
<script type="text/javascript" src="./backbone.js"></script>
</head>
<body>
<div>
<h1>Transcripts Data</h1>
<div id="dailyTranscripts-app">
<ul class="dailyTranscripts-list"></ul>
</div>
</div>
</body>
</html>
I've then coded my backbone.js file as the primer describes below:
var yesterday = moment (new Date()).add(-1, 'days').format('YYYY-MM-DD')
var yesterdaysDataURL = 'https://mihndbotblob.blob.core.windows.net/mihndbot-transcripts/finalTranscripts/dailyTranscripts/' + yesterday + '.json'
// Model class for each transcript iten
var DailyTranscriptsModel = Backbone.Model.extend({
defaults: {
type: null,
MessageID: null,
MessageTime: null,
MessageChannel: null,
MessageSenderID: null,
MessageSenderName: null,
ConversationID: null,
MessageText: null,
MessageRecipientID: null,
QuickReplyDisplayText: null,
QuickReplyPayload: null,
Question: null,
Answer: null,
FollowUpPrompts: null
}
});
// Collection class for the DailyTransctipts list endpoint
var DailyTranscriptsCollection = Backbone.Collection.extend({
model: DailyTranscriptsModel,
url: yesterdaysDataURL
});
// View class for displaying each dailyTranscripts list item
var DailyTranscriptsListItemView = Backbone.View.extend({
tagName: 'li',
className: 'dailyTranscripts',
initialize: function () {
this.listenTo(this.model)
},
render: function () {
var html = '<b>Message ID: </b> ' + this.model.get('MessageID');
html += '<br><b>Message Time: </b>' + this.model.get('MessageTime');
this.$el.html(html);
return this;
}
});
// View class for rendering the list of all dailyTranscripts
var DailyTranscriptsListView = Backbone.View.extend({
el: '#dailyTranscripts-app',
initialize: function () {
this.listenTo(this.collection, 'sync', this.render);
},
render: function () {
var $list = this.$('ul.dailyTranscripts-list').empty();
this.collection.each(function (model) {
var item = new DailyTranscriptsListItemView({model: model});
$list.append(item.render().$el);
}, this);
return this;
}
});
// Create a new list collection, a list view, and then fetch list data:
var dailyTranscriptsList = new DailyTranscriptsCollection();
var dailyTranscriptsView = new DailyTranscriptsListView({collection: dailyTranscriptsList });
dailyTranscriptsList.fetch();
The major changes I've made to the code (apart from some customisations) are to remove the templates the primer uses to create the views (I couldn't get them working) and I've removed the Backbone CRUD elements as I only require my app to read data from the server, not update or delete it.
The issue I have is that whilst I'm pulling back the JSON file from the server, none of the data is rendering in the HTLM <div> as expected, it's just blank.
I know that Backbone.js is retrieving the data as when I add .then(function() {console.log(dailyTranscriptsList);}); to the final dailyTranscriptsList.fetch() call I can see the data in the browser console:
You need to wrap all of your backbone.js code within jQuery's .ready()
// backbone.js
$(document).ready(function () {
// all your backbone.js code here
})
This causes your js to run after the DOM is ready, so Backbone will know how to find the elements it needs in order for views to work.
You could also move <script type="text/javascript" src="./backbone.js"></script> to the end of the page, right before </body>
When using list.js and tabletop for a sortable table taken from a Gdoc, I get the error: "Uncaught TypeError: Cannot read property 'childNodes' of undefined" on the first line of list.js.
Because the website I work for can only have JS uploaded, I need to write all my html using js or jquery, so it's a bit wonky. I think the error is being thrown because of the order I have everything, but I have tried moving things around to no avail. Everything is working other than the sorting.
Thanks!
HTML file
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
<script type="text/javascript" src="list.js-master/dist/list.min.js"></script>
<script type="text/javascript" src="src/tabletop.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div id="tablesetter"></div>
</body>
<script type="text/javascript">
var url = 'url to gdoc here';
$(document).ready( function(){
Tabletop.init( {key: url, callback: showInfo, parseNumbers: true} )})
function showInfo(data, tabletop){
$("#tablesetter").append('<h2>Table Working</h2><table><thead><th class="sort" data-sort="university">University</th><th class="sort" data-sort="no">Billionaires</th><th class="sort" data-sort="no2">Billionaires Rank</th><th class="sort" data-sort="rank">U.S. News Rank</th></thead><tbody class="list"></tbody></table>');
$.each(tabletop.sheets("Sheet1").all(), function(i, cat){
var htmltable = $('<tr><td class="university">' + cat.university + '</td>');
htmltable.append('<td class="no">' + cat.numberofbillionaires + '</td>');
htmltable.append('<td class="no2">' + cat.rankedbybillionaires + '</td>');
htmltable.append('<td class="rank">' + cat.usnewsranking + '</td></tr>');
htmltable.appendTo("tbody");
})
}
</script>
<script type="text/javascript" src="options.js"></script>
</html>
JS file
var options = {
valueNames: [ 'university', 'no' , 'no2' , 'rank']
};
var userList = new List('tablesetter', options);
The problem
var userList = new List('tablesetter', options); should be executed when the dom has an element of the list class; since in the question's code the list class default to list" , so such element should be <tbody class="list"> that is going to be appended to the #tablesetter only when the showInfo function receive data from google.
The solution
We ensure that the var userList = new List('tablesetter', options) statement executes after ( ie: at the end ) of the showInfo function; in other words move var userList = new List('tablesetter', options); from options.js just before the closing right bracket of the showinfo function.
More details
in the question's code when list.js tries to init() the dom is:
and list.list is still undefined when list.js defines it's getItemSource() functions:
with the proposed fix, at the var userList = new List('tablesetter', options); the dom is like:
and when defines it's getItemSource() functions the list.list can use the tbody as aspected:
If you look at this post, I'm sure your just missing some of the minimum requirements for list.js to function properly. Try to dynamically add the input with id and class of "search" as well with your other classes. Let me know if this helps.
https://stackoverflow.com/a/23078200/4812515
I have the following script , that is being used inside multiple views:-
$("#ChoiceTag, #ChoiceName").each(function () {
$(this).change(function () {
if ($("#ChoiceName").prop("checked")) {
$.getJSON("#Url.Content("~/Firewall/LoadCSName")",
function (CSData) {
var select = $("#GeneralCSID");
select.empty();
select.append($('<option/>', {
value: "",
text: "Select Name..."
}));
$.each(CSData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
select.val('#Model.CSIT360ID');
});
});
}
the script is exactly the same for all the views except for the controller name inside the following statement:-
$.getJSON("#Url.Content("~/Firewall/LoadCSName")",
so i am looking to move the above script and add it inside a separate .js file, and then reference this script , but i have the following two question:-
if i move the script to the script folder i need to dynamically reference the current controller name to build the URL, so is this possible
can i still reference the viewbag as i am currently doing ..
Thanks
If you move your Javascript into an external file you can't use your Razor syntax. Therefore, #Url.Content("~/Firewall/LoadCSName") will not resolve.
To overcome this add this to your view
<script type="text/javascript"> var AppPath = '#Url.Content("~/")'</script>
and reference it in your script like this
$.getJSON(AppPath + "Controller/Action")
Regarding the viewbag. Just put the viewbags value in a variable as shown above and your external file can reference it.
Hope this helps
Update
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript">
var AppPath = '#Url.Content("~/")';
var SomeValue = '#Model.CSIT360ID';
var ControllerName = "Firewall/LoadCSName";
</script>
<!--Move this to an external File-->
<script type="text/javascript">
$("#ChoiceTag, #ChoiceName").each(function () {
$(this).change(function() {
if ($("#ChoiceName").prop("checked")) {
$.getJSON(AppPath + ViewBagValue), function(CSData) {
var select = $("#GeneralCSID");
select.empty();
select.append($('<option/>', {
value: "",
text: "Select Name..."
}));
$.each(CSData, function(index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
select.val(SomeValue);
});
//end each
});
}
});
</script>
</body>
</html>
Update 2
This is how you could reference the controller in the url.content
<script type="text/javascript">
var AppPath = '#Url.Content("~/" + HttpContext.Current.Request.RequestContext.RouteData.Values["controller"])'
</script>
you can get the controller name this way:
#{
string controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
}
To access controller name from view use
#{
ViewContext.RouteData.Values["controller"].ToString();
}
To access controller instance one can use as follow
#{
(HomeController)ViewContext.Controller
}
One (slightly hacky) to make the current controller name accessible to JS would be to burn it into a global or namespaced variable assignment in the layout.
<script>
var app = window.app || {}
app.currentController = "#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString().toLower()";
</script>
Alternatively, a common way I work is to add classnames of the current controller and action to the body tag, to assist in DOM based routing in any javascript.
I have implemented a SettingsFlyout. From the view of this flyout, my app collection some info from user (firsname) and want to store it in roaming settings. This information get stored when user clicks a button the settings view and retrieved when in the beforeShow event for the flyout. These two events are setup in the ready function of the SettingsFlyout itself but for some reason I am getting following error.
0x800a138f - JavaScript runtime error: Unable to get property 'winControl' of undefined or null reference
on following line
var divtest = document.getElementById"test").winControl;
Similarly I also get
0x800a138f - JavaScript runtime error: Unable to set property 'onclick' of undefined or null reference.
Do you see anything I am doing wrong causing these issues?
Here is what I have in default.html
app.onsettings = function (e) {
e.detail.applicationcommands = {
"test": {
href: "/pages/settings/test/test.html",
title: "Test"
}
}
WinJS.UI.SettingsFlyout.populateSettings(e);
};
Here is the test.html itself.
<!DOCTYPE html>
<html>
<head>
<title></title>
<link href="/pages/settings/test/test.css" rel="stylesheet" />
<script src="/pages/settings/test/test.js"></script>
</head>
<body>
<div
data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{settingsCommandId:'test', width:'narrow'}">
<div class="win-header">
<div class="win-label">test</div>
</div>
<div class="win-content">
First Name: <input id="firstname" />
<br />
<input type="submit" value="Save" />
</div>
</div>
</body>
</html>
Here is the test.js file.
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/settings/test/test.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
var divtest = document.getElementById("test").winControl;
var firstname = document.getElementById("firstname");
document.getElementById("submit").onclick = function (e) {
//alert('hi');
roamingSettings.values["firstname"] = firstname.value;
}
divtest.addEventListener("beforeshow", function () {
firstname.value = roamingSettings.values["firstname"];
});
},
unload: function () {
// TODO: Respond to navigations away from this page.
},
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in viewState.
}
});
})();
There are no elements that have the id submit or test in your HTML.
The problem may be because this:
var divtest = document.getElementById("test").winControl;
looks for the HTML element with Id=test, it seems that you set
settingsCommandId:'test'
but it's not the same, so is should be:
<div id="test" data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{settingsCommandId:'test', width:'narrow'}">
I am writing a page with multiple jqGrids. My code follows a JavaScript MVC pattern which is going to provide an API for my HTML elements (including jqGrids). So, in the end of the day, I can create grids by calling my API. Something like:
var grid1 = new grid();
grid1.init();
var grid2 = new grid();
grid2.init();
I have done it with other javascript components and it worked great. However, when I create multiple jqGrid instances on the same page there is only one jqPager on the page attached to the last grid. Does anybody have an idea why?
Here is my code (Note that this is a simplified version, in reality I keep it separated in different .js files and also follow many other design patterns):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/themes/redmond/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.1.2/css/ui.jqgrid.css" />
</head><body>
<!-- IMPORT JS -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.1.2/js/i18n/grid.locale-en.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.1.2/js/jquery.jqGrid.min.js"></script>
<script>
$(document).ready(function() {
function grid() {
//=== LOCA VARIABLES ===//
var myGrid = $('<table>').attr( "id", "useraccount-search-datagrid");
var myPager = $("<div>").attr("id", "useraccount-search-datagrid-pager");
var localData1 = {
"page" : 1,
"totalRecords" : 5,
"pageSize" : 3,
"rows" : [
{ Name : "Name 1"},
{ Name : "Name 3"},
{ Name : "Name 2"}
]
};
function publicInit(){
$("body").append(myGrid, myPager);
myGrid.jqGrid({
pager : myPager,
data: localData1.rows,
datatype : "local",
colModel : [
{ name : 'Name', index : 'Name', width : "500"}
],
localReader: {
repeatitems: false
},
rowNum : 3,
viewrecords : true,
height : "auto",
ignoreCase : true
});
}
//=== REVEALING PATTERN===//
return {
init: publicInit
}
};
var grid1 = new grid();
grid1.init();
$("body").append("<br><br>"); //Add some spacing to distinguish between both grids
var grid2 = new grid();
grid2.init();
});
</script>
</body>
</html>
Any help would be highly appreciated.
It seems to me that your code produce <table> and <div> elements with the same id attributes. So the second grid var grid2 = new grid(); just add <table> and <div> elements which already exist on the page. It's a bug. All id attributes of all element on one HTML page must be unique. So the lines myGrid = $('<table>').attr( "id", "useraccount-search-datagrid"); and var myPager = $("<div>").attr("id", "useraccount-search-datagrid-pager"); must be changed.
If you need just to assign some unique ids you can use $.jgrid.randId() method used in jqGrid internally. The code could be
var myGrid = $("<table>").attr("id", $.jgrid.randId());
var myPager = $("<div>").attr("id", $.jgrid.randId());
Moreover I strictly recommend you to use name conversion used in JavaScript. If you need to use new operator to create an object you should rename the function grid to Grid.