I got a basic WebView in Xamarin.Forms like this:
<WebView AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All" x:Name="ChartWebView" Style="{StaticResource BackgroundStyle}">
<WebView.Source>
<HtmlWebViewSource Html="{Binding ChartHTML}" />
</WebView.Source>
</WebView>
I use the WebView to display a Chart.js diagram which works perfectly fine. On my page i got a button where the user can request data.
private async Task RequestData()
{
//Doing some stuff to get data ...
BuildChartHTML();
}
private void BuildChartHTML()
{
var html = GetChartJSConfigString();
Device.BeginInvokeOnMainThread(() =>
{
ChartWebView.Source = new HtmlWebViewSource
{
Html = html
};
});
}
However, on iOS only, everytime on exactly the 10th request/reload the WebView gets blank. It also stays blank after that. I need to re-navigate to this page to get it up and running again. I tried adjusting the height on WebView.Navigated as described in this thread, without success.
The problem doesn't accure on Android with the same code base.
Open to any workarounds if this is a framework bug.
PS: I obviously made sure that the html I'm loading is not broken. I loaded the same data 10 times and i compared the html loaded on the 10th time where the WebView broke. It was exactly the same HTML string.
Turned out to be a problem with iOS WKWebView and the use of HTML canvas (chart.js is renderered on a canvas).
After debugging into my WebView (stupid me not thinking about that possiblity before), i found out that the canvas memory exceeded the limit. With the help of a solution posted here i managed to avoid this problem.
Keep in mind this solution is a little bit hacky. Basically what I've done is, as pointed out in the link above, i "deleted" the canvas everytime i reload my chart. By "deleting" i mean setting the canvas to width and height to zero. Applied to my code the solution looks like this:
Inside my javascript that runs in the browser i added a function like this:
function deleteCanvas() {
//Get the main canvas where the chart is rendered to
var chart = document.getElementById('chart');
chart.height = 0;
chart.width = 0;
}
And then everytime i call my BuildChartHTML() function i call this method in my c# code like this:
Device.BeginInvokeOnMainThread(() =>
{
ChartWebView.Source = new HtmlWebViewSource
{
Html = html
};
ChartWebView.Eval("deleteCanvas()");
});
In NativeScript, how can I get the value of a textfield using JavaScript (not TypeScript/Angular)?
XML:
I've tried various combinations of "getViewByID()" but nothing is working (perhaps I didn't "require" right libraries?). Not looking to do 2-way binding; just get the value (print to the console).
Just as a reminder, it's usually a good idea to share some code with your question to show what you have already tried.
In this example you could have shared some xml markup for instance.
Anyways to get the value of a textfield you would have something like this.
var view = require("ui/core/view");
function pageLoaded(args) {
var page = args.object;
var textfield= view.getViewById(page, "textfieldID");
}
After this you should be able to do :
var text = textField.text;
Historically I’ve used the following approach to switch an iOS status bar to use white text.
<Page loaded="loaded">
<Page.actionBar>
<ActionBar title="Whatever"></ActionBar>
</Page.actionBar>
</Page>
var frameModule = require("ui/frame");
exports.loaded = function(args) {
var page = args.object;
if (page.ios) {
var navigationBar = frameModule.topmost().ios.controller.navigationBar;
navigationBar.barStyle = UIBarStyle.UIBarStyleBlack;
}
};
Unfortunately this approach doesn’t seem to work anymore after the NativeScript 2.0 release. Any idea what might be up?
Thanks.
The issue is already fixed in our #next build. We will release it officially as 2.0.1 most probably next week.
Well, I've been reading the documentation and I believe that I'm calling functions and passing parameters correctly, but for the life of me I can't get this simple UI code to work.
I'm generating a UI for a Spreadsheet using the following code:
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
// Absolute panel for setting specific locations for elements
var panel = gui.createAbsolutePanel();
// Equipment ID#s Label
var equipmentIDLabel = gui.createLabel("Equipment ID#s");
equipmentIDLabel.setHorizontalAlignment(UiApp.HorizontalAlignment.CENTER);
equipmentIDLabel.setSize("20px", "125px");
equipmentIDLabel.setStyleAttributes({background: "SteelBlue", color: "white"});
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
gui.add(panel);
return gui;
}
function getUIdata(eventInfo) {
// I know how to get the data from each element based on ID
}
It generates the Absolute Panel correctly when checkOut() is called, but the EquipmentIDLabel is never added to the panel. I am basing the code on the simplistic design I created in the GUI builder (that will be deprecated in a few days, which is why I am writing the code so that I can change it later):
So what exactly is going wrong here? If I can figure out how to add one element, I can infer the rest by looking at the docs. I've never been any good at GUI development!
You could maybe use grid as an interesting alternative... here is an example :
// define styles
var labelStyle = {background: "SteelBlue", color: "white",'textAlign':'center','line-height':'20px','vertical-align':'middle','font-family':"Arial, sans-serif",'fontSize':'10pt'};// define a common label style
var fieldStyle = {background: "white", color: "SteelBlue",'font-family':"Courrier, serif",'fontSize':'11pt'};// define a common label style
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
var panel = gui.createAbsolutePanel().setStyleAttribute('padding','10px');
var grid = gui.createGrid(4,2).setWidth('300').setCellPadding(10);//define grid size in number of row & cols
var equipmentID = ['equipmentIDLabel','equipmentIDLabel1','equipmentIDLabel2','equipmentIDLabel3'];// define labels in an array of strings
for(var n=0 ;n<equipmentID.length ; n++){;// iterate
var equipmentIDLabel = gui.createLabel(equipmentID[n]).setWidth('125').setStyleAttributes(labelStyle);
var equipmentIDField = gui.createTextBox().setText('Enter value here').setName(equipmentID[n]).setSize("125", "20").setStyleAttributes(fieldStyle);
grid.setWidget(n,0,equipmentIDLabel).setWidget(n,1,equipmentIDField);
}
gui.add(panel.add(grid));
return gui;
}
It looks like the absolute panel offset method is a little capricious and take control of your positioning, in my tests I have been able to position panels that are visible in the following way:
panel.add(equipmentIDLabel);
panel.add(equipmentIDField,150,0);
panel.add(otherLabel);
panel.add(otherField, 150, 20);
Try it out with trial and error, you may get the UI you need, if not I would move to an alternate layout, verticalPanel is a little better behaved and of course you can use forms as well.
Another small bug is that you inverted the length and hight in equipmentIDLabel.setSize("20px", "125px");
Let me know if I can be of more assitance
The specific problem in your code is the following line :
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
Simply change it to : panel.add(equipmentIDLabel);
..and you will see the field (at position 0,0).
As patt0 observes, you can then add OTHER components and use positioning. It seems to be a limitation of adding the first field to an absolutePanel.
Of course, the Google Script gui is now deprecated (since December 2014) but I was interested to try your code and see that it still basically executes (as at Feb 2016).
We have a page containing a table with 26 rows. Each row will contain either an <input> or <select> element, depending on the data we're binding to. When binding to elements that contain between 5-30 options, it takes a page about 5 seconds to render. If I remove the binding, the page renders in under a second.
Is there a known performance issue when binding to Ember.Select views? Or, could I be doing it incorrectly? I'm using Firefox 22. IE9 is about twice as slow. The CPU is not pegged during this time. I'm using ember 1.0rc6.
Template snippet:
{{#if pa.isPickList}}
{{view Ember.Select viewName="select" contentBinding="pa.options" selectionBinding="pa.selected"}}
{{else}}
{{input valueBinding="pa.selected"}}
{{/if}}
I worry that the async nature of how I'm fetching the model could be causing inefficiencies. Perhaps the binding and async events are interacting inefficiently.
Salesforce.com is the backend. From what little I know about promises, I'm wondering if I need to fetch the server data in a promise. I'm not sure how to do this.
Here's how I'm currently fetching the data in my Route:
App.IndexRoute = Ember.Route.extend({
model: function(params){
var otherController = this.controllerFor('selectedProducts');
var ar = Ember.A(); //create an array
var arg = '0067000000PNWrV';
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.ProductPricingLookupController.loadOpportunityProducts}',
arg,
function myHandler(result, event) {
console.info('got results!!! ' + result.length);
for(var i = 0; i < result.length; i++)
{
var p = result[i];
var sfProd = App.ProductResult.create({content: p});
ar.pushObject(sfProd);
}
},
{escape: false} //some of the names have ampersands!!
);
return ar;
}
}
Thanks in advance for helping a newbie learn the ways of javascript and Ember.
Update
Here is working example of this issue. I have 5 picklists each with 60 options. This take 2-3 seconds to render on my machine. I realize these are decently large numbers but hopefully not unreasonable. Increase the number of picklist elements or options and you can easily hit 5 seconds.
Also, moving my server-model-fetching to a promise did not affect performance.
Andrew
It's a little hard to guess at performance problems like this without looking at it in a profiler. You can try creating a profile in Chrome dev tools to see what method is taking the most amount of time. Or create a jsbin which has the same issue.
One potential issue is that the array that you bind to is being built at the same time when the bindings are connected. This shouldn't be an issue with rc.6. What version of Ember are you on?
Regards to promises, your model hook should return a promise that wraps your async call, like so.
model: function(params) {
var promise = Ember.Deferred.create();
var myHandler = function(result, event) {
var model = Ember.A();
// populate the model
promise.resolve(model)
}
var arg = '0067000000PNWrV';
Visualforce.remoting.Manager.invokeAction(..., myHandler);
return promise;
}
If the bindings were firing too early/often, loading the model in a promise like this would help.
Finally try setting Ember.STRUCTURED_PROFILE to true. This will show you exactly how long the templates are taking to render.
Edit: After the the jsfiddle
I dug into this a little more. This is a known issue with Ember.Select. The default implementation creates SelectOption views for each option inside the select to allow databinding of the option items itself. Creating those many views is what takes the time.
However the typical usage will rarely need binding to the option items only to the whole list itself. And this appears to be the common way to bridge the performance gap.
I found a gist that uses option tags instead of SelectOption views.
Here's your updated jsfiddle. I upped the lists to 10 with 100 items each. The list renders in about 150ms for me now.