I am trying to render some HTML code in flutter web which takes a dynamic value of sessionID and that's the reason I cannot have the html file as a asset. I've also tried a lot of packages but they are not working in web, in mobile its working fine.
I'm basically implementing Mastercard Hosted Checkout but it's not getting rendered directly in flutter web.
I'd tried IFrameElement but there's some problem with it, it immediately breaks off and the code doesn't works in flutter web. Maybe because its being handled in initState. Anyway here's the code of IframeElement please let me know if there's some way to deal with it.
late html.IFrameElement _element;
void initState() {
super.initState();
createSession().then((sessionId) {
setState(() {
_sessionId = sessionId;
_sessionId = _sessionId;
});
}).catchError((error) {
debugPrint(error.toString());
});
_element = html.IFrameElement()
..style.border = 'none'
..srcdoc = """
<html>
<head>
<script src="https://test-network.mtf.gateway.mastercard.com/static/checkout/checkout.min.js" data-error="errorCallback" data-cancel="cancelCallback"></script>
<script type="text/javascript">
function errorCallback(error) {
console.log(JSON.stringify(error));
}
function cancelCallback() {
console.log('Payment cancelled');
}
Checkout.configure({
session: {
id: '$_sessionId'
}
});
</script>
</head>
<body>
...
<div id="embed-target"> </div>
<input type="button" value="Pay with Embedded Page" onclick="Checkout.showEmbeddedPage('#embed-target');" />
<input type="button" value="Pay with Payment Page" onclick="Checkout.showPaymentPage();" />
...
</body>
</html>
""";
// ignore:undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'example',
(int viewId) => _element,
);
}
Related
I am looking for a way to disable the popup message which shows when using window.showDirectoryPicker. This page is served from localhost via WebView2 component in a WPF app.
<!DOCTYPE html>
<html>
<body>
<div class="fl" style="margin: 0 0 2rem 0"><button id="addToFolder">Give access to folder</button></div>
</body>
</html>
<script>
let directory;
document.getElementById('addToFolder').addEventListener('click', async () => {
try {
directory = await window.showDirectoryPicker({
startIn: 'desktop'
});
for await (const entry of directory.values()) {
let newEl = document.createElement('div');
newEl.innerHTML = `<strong>${entry.name}</strong> - ${entry.kind}`;
document.getElementById('folder-info').append(newEl);
}
} catch (e) {
console.log(e);
}
});
</script>
Note that I already have full file system access via the WPF app, so its not a security concern.
I am trying to explore on web NFC and found a simple sample (https://googlechrome.github.io/samples/web-nfc/). So, I copy the sample code to test it on local:
<html><head>
<title>Web NFC Sample</title>
<script>
// Add a global error event listener early on in the page load, to help ensure that browsers
// which don't support specific functionality still end up displaying a meaningful message.
window.addEventListener('error', function(error) {
if (ChromeSamples && ChromeSamples.setStatus) {
console.error(error);
ChromeSamples.setStatus(error.message + ' (Your browser may not support this feature.)');
error.preventDefault();
}
});
</script>
<link rel="stylesheet" href="Web%20NFC%20Sample_files/main.css">
</head>
<body>
<button id="scanButton">Scan</button>
<button id="writeButton">Write</button>
<script>
var ChromeSamples = {
log: function() {
var line = Array.prototype.slice.call(arguments).map(function(argument) {
return typeof argument === 'string' ? argument : JSON.stringify(argument);
}).join(' ');
document.querySelector('#log').textContent += line + '\n';
},
clearLog: function() {
document.querySelector('#log').textContent = '';
},
setStatus: function(status) {
document.querySelector('#status').textContent = status;
},
setContent: function(newContent) {
var content = document.querySelector('#content');
while(content.hasChildNodes()) {
content.removeChild(content.lastChild);
}
content.appendChild(newContent);
}
};
</script>
<h3>Live Output</h3>
<div id="output" class="output">
<div id="content"></div>
<div id="status">Web NFC is not available.
Please make sure the "Experimental Web Platform features" flag is enabled on Android.</div>
<pre id="log"></pre>
</div>
<script>
if (/Chrome\/(\d+\.\d+.\d+.\d+)/.test(navigator.userAgent)){
// Let's log a warning if the sample is not supposed to execute on this
// version of Chrome.
if (89 > parseInt(RegExp.$1)) {
ChromeSamples.setStatus('Warning! Keep in mind this sample has been tested with Chrome ' + 89 + '.');
}
}
</script>
<script>
log = ChromeSamples.log;
if (!("NDEFReader" in window))
ChromeSamples.setStatus(
"Web NFC is not available.\n" +
'Please make sure the "Experimental Web Platform features" flag is enabled on Android.'
);
</script>
<script>scanButton.addEventListener("click", async () => {
log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
log("> Scan started");
ndef.addEventListener("readingerror", () => {
log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
log(`> Serial Number: ${serialNumber}`);
log(`> Records: (${message.records.length})`);
});
} catch (error) {
log("Argh! " + error);
}
});
writeButton.addEventListener("click", async () => {
log("User clicked write button");
try {
const ndef = new NDEFReader();
await ndef.write("Hello world!");
log("> Message written");
} catch (error) {
log("Argh! " + error);
}
});
</script>
</body></html>
But when I run it, it shows Web NFC is not available. Please make sure the "Experimental Web Platform features" flag is enabled on Android. on the message. When I click on "scan" button, it shows Argh! ReferenceError: NDEFReader is not defined.
May I know why the sample code work well when it is on https://googlechrome.github.io but can't work when I have it on my local PC? Thank you.
As documented in https://web.dev/nfc/#security-and-permissions, Web NFC is only available in secure browsing contexts. It means you either have to serve your webpage over https:// or localhost such as http://127.0.0.1 or http://localhost.
If you have installed npm, you can use npx http-serve.
If you have installed Python 2, use python -m SimpleHTTPServer
If you have installed Python 3, use python -m http.server
I have a page that is dynamically populated with AJAX once the page is loaded in asp.net core.
I have to use AJAX because I am populating the page from different sources using id parameter to get value and the page is populated. The HTML pages are working fine and the data are properly displayed.
So I tried using Rotativa base on this tutorial, I was able to get the pdf working but the PDF is empty because the page has not loaded before the PDF is generated.
The idea now is that if I could have a button on the page to convert the page to pdf and users can download.
Is there a way to achieve this?
The idea now is that if I could have a button on the page to convert the page to pdf and users can download.
Is there a way to achieve this?
You can use PDF.Core package to implement it, you can find it in Nuget.
Below is a working demo:
View:
<h1>Test</h1>
<input id="download" type="button" value="download" />
<script src="~/lib/jquery/dist/jquery.js"></script>
<script>
$(function () {
$("#download").on("click", function () {
var markup = document.documentElement.innerHTML;
$.ajax({
type: "post",
url: "/Home/Download",
data: { "htmlContent": markup },
success: function () {
window.location = '#Url.Action("Download", "Home")';
}
})
})
});
</script>
Controller
public IActionResult Download(String htmlContent)
{
if (!string.IsNullOrEmpty(htmlContent))
{
IronPdf.HtmlToPdf Renderer = new IronPdf.HtmlToPdf();
Renderer.RenderHtmlAsPdf(htmlContent).SaveAs("html-string.pdf");
return Ok();
}
else
{
var stream = new FileStream(Path.Combine(_hostingEnvironment.ContentRootPath, "html-string.pdf"), FileMode.Open);
return new FileStreamResult(stream, "application/pdf");
}
}
Our team Chose IronPDF and it worked based on the MVC tutorial posted:
https://ironpdf.com/docs/questions/asp-net-mvc-pdf-binary/
public FileResult GetHTMLPageAsPDF(long id) {
//Create a PDF Document
var PDF = Renderer.RenderHtmlAsPdf("<h1>html as required</h1>");
//return a pdf document from a view
var content = PDF.BinaryData;
Response.AppendHeader("Content-Length", content.Length.ToString());
Response.AppendHeader("Content-Disposition", "inline; filename=Document_" + id + ".pdf");
return File(content, "application/pdf;");
}
I later went for pugpdf because I couldnt afford IronPDF. Its a good package though.
Pugpdf did the job for me
public async Task<IActionResult> Download(String htmlContent)
{
if (!string.IsNullOrEmpty(htmlContent))
{
var renderer = new HtmlToPdf();
renderer.PrintOptions.Title = "Statement";
var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent);
pdf.SaveAs(Path.Combine(_webHostEnvironment.ContentRootPath, "html-string.pdf"));
return Ok();
}
else
{
var stream = new FileStream(Path.Combine(_webHostEnvironment.ContentRootPath, "html-string.pdf"), FileMode.Open);
return new FileStreamResult(stream, "application/pdf");
}
}
This is my view and controller. I have converted code from c# to vb the code was working perfectly in C# but i dont know why this java script is not working in vb. I started debugging but controllers never get called when i type something in search box.
Code for View
#ModelType PrudentHealthCare.Product
#Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Search</title>
</head>
<body>
<div>
#Using (Html.BeginForm())
#Html.HiddenFor(Function(model) model.id)
#<input type="text" id="search" placeholder="Search for a product" required />
#<input type="submit" value="Go" id="submit" />
End Using
</div>
</body>
</html>
<link href="~/Content/AutoComplete/jquery-ui.css" rel="stylesheet" />
<script src="~/Content/AutoComplete/jquery-ui.js"></script>
<script src="~/Content/AutoComplete/jquery-1.9.1.js"></script>
<script type="text/javascript">
var url = '#Url.RouteUrl( "DefaultApi" , New With { .httproute = "", .controller = "ProductApi" })';
$('#search').autocomplete({
source: function (request, response) {
$.ajax({
url: url,
data: { query: request.term },
dataType: 'json',
type: 'GET',
success: function (data) {
response($.map(data, function (item) {
return {
label: item.Description,
value: item.Id
}
}));
}
})
},
select: function (event, ui) {
$('#search').val(ui.item.label);
$('#Id').val(ui.item.value);
return false;
},
minLength: 1
});
</script>
ProductApiController
Imports System.Web.Mvc
Namespace Controllers
Public Class ProductApiController
Inherits Controller
<HttpGet>
Public Function GetProducts(Optional query As String = "") As IEnumerable(Of Product)
Dim xyz As String
xyz = query
End Function
End Class
End Namespace
jQuery UI has an AutoComplete widget. The autocomplete widget is quite nice and straight forward to use. In this post, how to integrate the AutoComplete widget with an ASP.NET MVC application.
The first step is to add the jQuery scripts and styles. With ASP.NET MVC 4, the following code does the work:
#Styles.Render("~/Content/themes/base/css")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryui")
Using the AutoComplete widget is also simple. You will have to add a textbox and attach the AutoComplete widget to the textbox. The only parameter that is required for the widget to function is source. For this example, we will get the data for the AutoComplete functionality from a MVC action method.
$(document).ready(function () {
$('#tags').autocomplete(
{
source: '#Url.Action("TagSearch", "Home")'
});
})
In the above code, the textbox with id=tags is attached with the AutoComplete widget. The source points to the URL of TagSearch action in the HomeController: /Home/TagSearch. The HTML of the textbox is below:
<input type="text" id="tags" />
When the user types some text in the textbox, the action method - TagSearch is called with a parameter in the request body. The parameter name is term. So, your action method should have the following signature:
public ActionResult TagSearch(string term)
{
// Get Tags from database
string[] tags = { "ASP.NET", "WebForms",
"MVC", "jQuery", "ActionResult",
"MangoDB", "Java", "Windows" };
return this.Json(tags.Where(t => t.StartsWith(term)),
JsonRequestBehavior.AllowGet);
}
I'm trying to learn some stuff with Knockout by following the examples.
I've followed the loading and saving data tutorial and read the docs on Loading and Saving JSON Data.
Using the code in these examples, I can't seem to overwrite the JSON file. I tried setting permissions to 777 to make sure that wasn't the problem.
On "success," it just seems to return the data in the file. I confirmed this by loading the HTML file, manually editing the JSON file, deleting tasks, and clicking save. The result I saw in my console was the data from the manual edit of the JSON file.
I have this hosted on my server right now: index.html, test.json.
For the sake of posterity, here is that code:
HTML
<!doctype html>
<html>
<body>
<h3>Tasks</h3>
<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
Delete
</li>
</ul>
You have <b data-bind="text: incompleteTasks().length"> </b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
<button data-bind="click: save">Save</button>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() && !task._destroy });
});
// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.destroy(task) };
self.save = function() {
var data = ko.toJSON({ tasks: self.tasks });
$.post('test.json', data, function(returnedData) {
console.info(returnedData);
});
/*
$.ajax("test.json", {
data: ko.toJSON({ tasks: self.tasks }),
type: "post", contentType: "application/json",
success: function(result) { console.info(result) }
});
*/
};
// Load initial state from server, convert it to Task instances, then populate self.tasks
$.getJSON("test.json", function(allData) {
var mappedTasks = $.map(allData, function(item) { return new Task(item) });
self.tasks(mappedTasks);
});
}
ko.applyBindings(new TaskListViewModel());
</script>
</body>
</html>
JSON
[{"title":"Wire the money to Panama","isDone":true},{"title":"Get hair dye, beard trimmer, dark glasses and \"passport\"","isDone":false},{"title":"Book taxi to airport","isDone":false},{"title":"Arrange for someone to look after the cat","isDone":false}]
The form is working properly, it's posting the correct JSON to the server (you can see this in the browser's dev tools). But because it's just a JSON file on the server, you're not able to overwrite it by simply posting to it. Instead, you'll need to create a web service endpoint on the server that you can post the data to, and the service will then save the file on the server's file system.