how to pass data from xamarin shared project to an html - xamarin

I have a webview in my page where I'm showing a chart(Fusion Chart).
I wrote a html page with js function as follows:
<html lang="en">
<head>
<script src="file:///android_asset/fusioncharts.js"></script>
<script src="file:///android_asset/fusioncharts.charts.js"></script>
</head>
<body>
<div id="chart-container"></div>
<script>
function loadChart(chartData) {
const dataSource = {
chart: {
theme: "fusion",
"showPlotBorder": "1",
"plotBorderColor": "#ffffff"
},
data: chartData
};
FusionCharts.ready(function () {
var myChart = new FusionCharts({
type: "column2d",
renderAt: "chart-container",
width: "100%",
height: "100%",
dataFormat: "json",
dataSource
}).render();
});
}
loadChart(chartData);
</script>
</body>
</html>
I need to pass data to the loadchart function from my shared project with the help of my webview. Is this possible?

There are so many ways of doing this on Android, though I would caution you to test it well on different devices depending on what default browser is being used for the WebView.
Luckily, since you are using Xamarin Forms, you could just use the Javascript Evaluation function that enables you to just put your JS code inside the function. And then time it right, and you can call a JS function which will take values from your C#.
Here's the documentation by MS on the functions
Eval() or EvaluateJavaScriptAsync().
Here are some examples of it's usage:
webView.EvaluateJavaScriptAsync(string.Format("document.getElementById(\"{0}\").value = \"{1}\"", "langs1", from));
webView.EvaluateJavaScriptAsync(string.Format("DDMENU(0)"));
Let me know if you have any questions!

Related

Kendo custom widget with MVVM and init event - how?

I try to implement a custom kendo widget with "Init" event. If the widget is initialized with JavaScript, the event is triggered. But when the widget is initialized with data attributes - it doesn't. What do I miss?
Sample: http://dojo.telerik.com/UQoWi
Note: As you can see, I've tried to handle the "init" event according to the KendoUI's documentation:
... data-init="onInit" data-bind="events: { init: onInit }" ...
Suppliment: I'd like to add that i completely understand WHY there is not an init binder already. It doesn't really make sense. As a ViewModel can be BOUND to many different things in Kendo, an init callback inside a Viewmodel for a Widget just doesn't make sense. That's why the dataBinding and dataBound is used. When the widget is created it DOES invoke the handler for data-init="", it just has to be in scope. That's the one time call for a widget. The ViewModel Observable can be bound and unbound to many different widgets. How would the system know that the Observable ViewModel is supposed to be strictly tied to that one specific widget? It wouldn't unless you update the Widget to had an internal data source and observable.
If this Observable is bound to multiple of your custom widgets, the onInit will be called for each widget. It will not be called for any of the built in widgets as they don't trigger(INIT). That's easily fixed by overloading the fn.init function, or extending them. Or, even creating a global onInit function that is used in the data-init element attribute, since you can get access to the widget itself through the parameters. $(element).data("kendoWidget") etc.
Hope this helps! It's certainly helped me understand everything.
I've been able to do what you want. It seems I was greatly mistaken about what the data-bind="events: {}" is for. The handlers within that definition appear to be handlers for the HTML events. So we can add a new 'init' handler to the Widget system itself. I've been able to get your example to work with the following code below.
The key is to add a NEW binder for a Kendo Event called 'init'.
kendo.data.binders.widget.init =
kendo.data.Binder.extend({
function(widget, bindings, options) {
Binder.fn.init.call(this, widget.element[0], bindings, options);
this.widget = widget;
},
refresh: function () {
var init = this.bindings.init.get();
}
});
Then we can use the data-bind="init: onInitFromMVVM" to bind to a one time even call. This will only be a one time call because it's only triggered in the init of the Widget.
I went through the source code over and over and the events: {} confused me until I started reading the documentation. Then I realized that almost all the handlers inside events: {} were for HTML events. Things like visible, onmouseover, onmouseexit, etc. So I then created a new binder called 'init', and your code worked after that.
The code below produces the following output:
widget init proof
global init proof
init mvvm proof
It even calls the handler for data-init in the global scope.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.common.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.default.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2015.3.930/styles/kendo.mobile.all.min.css">
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2015.3.930/js/angular.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2015.3.930/js/jszip.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2015.3.930/js/kendo.all.min.js"></script>
<script>
var binders = kendo.data.binders,
Binder = kendo.data.Binder,
proxy = $.proxy,
ui = kendo.ui,
Widget = ui.Widget,
INIT = 'init';
(function ($) {
kendo.data.binders.widget.init =
kendo.data.Binder.extend({
init: function(widget, bindings, options) {
Binder.fn.init.call(this, widget.element[0], bindings, options);
this.widget = widget;
},
refresh: function () {
var init = this.bindings.init.get();
}
});
var MyWidget = Widget.extend({
options: {
name: 'MyWidget',
},
events: [
INIT
],
init: function (element, options) {
var that = this;
console.log('widget init proof');
Widget.fn.init.call(this, element, options);
that.trigger(INIT);
}
});
ui.plugin(MyWidget);
})(jQuery);
$(document).ready(function () {
var observableModel = new kendo.data.ObservableObject({
onInitVM: function (e, opts) {
console.log('init mvvm proof');
}
});
kendo.bind($('#myWidgetMVVM'), observableModel);
});
</script>
</head>
<body>
<div>Open console...</div>
<input type="hidden" id="myWidgetMVVM" data-init="onInit" data-role="mywidget" data-bind="init: onInitVM" />
<script>
function onInit(element, options) {
console.log("global init proof");
}
</script>
</body>
</html>

Creating JQuery plugin

I've followed a tutorial to create a Website Menu, this involves JQuery to provide some transitions.
I've got it working as intended, but to prove I understand this new code and framework, and also, to follow development guidelines, I want to move to the Menu code to a plug-in.
Working (not-plug-in) version:
This appears in the .ascx, along with a UL tag, ID = MainMenu
<script type="text/javascript">
NavBarMenu();
</script>
In another file, NavBar.js, the following code is used to associate some JQuery events:
function NavBarMenu() {
$(function() {
var $menu = $('#MainMenu');
var $menu_items = $menu.children('li');
...
Not working version:
Now the plug-in code is created, the NavBarMenu function is called like this from the .ascx:
<script type="text/javascript">
$("#MainMenu").NavBarMenu();
</script>
In NavBar.js I now have:
(function($) {
$.fn.NavBarMenu = function() {
var $menu_items = this.children('li');
However, the $menu_items variable is unpopulated?
Shouldn't this (2nd example) be equivalent to $('#MainMenu') (1st example)
I followed this example, where a JQuery selector is switched for the this pointer. http://learn.jquery.com/plugins/basic-plugin-creation/
Thanks in advance :D
There must be other factor affecting my implementation, I will revisit it.
I have created 2 JSFiddle pages, as part of my investigation and it has proved that the JQuery Selector can be swapped for the this pointer in a plug-in.
Fiddle detailing 1st example: http://jsfiddle.net/rL7zpr15/1/
$('input[type=button]').click( function() {
$( "div" ).css( "background", "green" );
});
Is equivalent to
Fiddle detailing 2nd example: http://jsfiddle.net/hds7advx/
$.fn.greenify = function() {
this.css( "background", "green" );
};
$('input[type=button]').click( function() {
$( "div" ).greenify();
});

Load zebra strip in ajax loaded table

I tried to apply a zebra strip with an ajax loaded table but it's not work. I tried googling some suggestion over the net but no luck. Here's my code:
CSS:
<style>
.odd{background:#eeeeee}
</style>
Javascript:
<script src="../jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("tr:even").addClass("even");
$("tr:odd").addClass("odd");
});
//supplier ajax viewer
$(document).ready(function(stripTable) {
$("#supplier_viewer").load("inc/stock_view.php");
$('tr:odd',this).addClass("odd");
var refreshId = setInterval(function() {
$("#supplier_viewer").load('inc/stock_view.php?randval='+ Math.random());
}, 10000);
$('tr:odd',this).addClass("odd");
$.ajaxSetup({ cache: false });
});
</script>
And this is where the table is loaded.
HTML:
<div id="supplier_view"></div>
I've tried to add
$('tr:even',this).addClass("even");
to the load stage but not work. Please suggest.
You are applying the classes to the element before they are actually loaded.
Try applying these classes when the loaded event is fired.
I would also recommend to use FireBug to view the generated html and see if the classes are really applied to the dynamically loaded data. (which I highly suspect not)
Once the data is loaded, you need to execute these two lines
$("tr:even").addClass("even");
$("tr:odd").addClass("odd");
But only after the data has been loaded to the div

What is causing gray space on a Google Map using v3 API?

I'm trying to load a map as per the example in the Google documentation, but it's not loading. I tried using resize, but it's not loading correctly. This map is behind a tab rendered with the Prototype JavaScript Framework which magento uses. It loads correctly when not behind a tab.
<style type="text/css">
#map_container { height:500px; width:700px;margin:0;}
</style>
<div id="map_container">
<div id="map_canvas" style="width:500px;height:500px;"></div>
</div>
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?key=APIKEY&sensor=true">
</script>
<script type="text/javascript">
Event.observe( window, "load", function() {
var myOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
;
google.maps.event.trigger(map, "resize");
});
</script>
The map is shown with grey parts that cover most of the map and the UI elements are not fully initialized. I tried using google.maps.event.trigger(map, "resize");, but it does not seem to do anything. This div is inside a lot of divs.
Example how to add new tab "GMaps" in Magento "Product Edit" (new tab "id" is 'product_info_tabs_GMaps')
PHP part
class My_Gmaps_Block_Adminhtml_Tabs_Gmaps extends Mage_Adminhtml_Block_Widget_Form
public function __construct() {
parent::__construct();
$this->setTemplate('my/gmaps/tabs/gmaps.phtml');
}
/............................./
}
Template part 'pwron/gmaps/tabs/gmaps.phtml':
<style>#map_canvas {width:100%; height:600px;}</style>
<div class="map" id="map_canvas"></div>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var GMaps = Class.create();
GMaps.prototype = { .................... }
var gmaps = null;
function switchGMapsTab(tab){
if ( tab.tab.container.activeTab.id == 'product_info_tabs_GMaps'){
if (!gmaps){
gmaps = new GMaps({});
gmaps.update();
}
}
}
varienGlobalEvents.attachEventHandler('showTab', switchGMapsTab); <script>
trouble way
1. Created Map
2. Tab showed (not loads all tiles)
best way
1. Tab showed
2. Created Map
I had the same problem as you. But I managed to find the solution with this simple code.
First, go to the file where you put the tab template, search for the <li> tag that load your map tab and put this inside:
<li onclick="reloadmap()">
And in the map script right after the
google.maps.event.addDomListener(window, 'load', initialize);
put this:
function reloadmap(){
//when you resize the map, you lose your zoom and your center
//so you need to get them again here
z = map.getZoom();
c = map.getCenter();
google.maps.event.trigger(map, 'resize');
//and set them again here
map.setZoom(z);
map.setCenter(c);
}

Getting jQuery TipTip to work with ajax loaded content

I am using the jQuery TipTip plugin to display tooltips on hrefs using data from the "Title" tag.
Here is the code i am using to invoke TipTip
<script type="text/javascript" src="jquery.tipTip.js"></script>
<!-- ToolTip script -->
<script type="text/javascript">
$(function(){
$(".someClass").tipTip({maxWidth: "auto", edgeOffset: 10});
});
</script>
<!-- End ToolTip script -->
and in the body
sample content. sample,stuff.
This works fine as standalone example. However, when i set the script up to load the content into the body via ajax (using sample.html that contains the original body code), the ToolTip stops working.
<script type="text/javascript">
//loading sample ajax data
$(document).ready(function(){
$('#remote').load('sample.html');
});
</script>
Browsing in the TipTip forums, someone mentioned this could work using the jQuery .live function, but having read the documentation, i dont understand how im supposed to implement this with my code. I understand that jquery-live is an event handler, so supposedly, i could call in the data via ajax as the primary event and then apply TipTip as a secondary event, but i cant figure out how to implement this, and dont know if im definitely going down the right path.
Could someone please advise me?
An easy solution would be to create a function that activates TipTip:
function activateTipTip() {
$(".someClass").tipTip({maxWidth: "auto", edgeOffset: 10});
}
$(document).ready(function(){
activateTipTip();
$('#remote').load('sample.html', function() {
activateTipTip();
});
});
Not very elegant, but should work though.
This code will make it so that any link that has a title attribute will have TipTip's functionality applied to it:
$('a[title]').live('mouseover', function()
{
$(this).tipTip({
delay: 200,
maxWidth: '400px'
});
$(this).trigger('mouseenter');
});
Source: https://drew.tenderapp.com/discussions/tiptip/73-tiptip-and-jquery-live
This is my solution for this problem:
$(ElementParent).on('mouseover', YourElementSelector, function()
{
if($(this).data('hasTipTip') !== true)
{
$(this).tipTip(TipTipOptions);
$(this).data('hasTipTip', true);
$(this).trigger('mouseover');
}
});

Resources