How do I build an Asp.Net Core Razor page control that allows users to sign their names? - asp.net-core

I am building an Asp.Net Core web application using Razor.
The intended audience for this app will be using it on tablets.
Part of the application consists of several pages/forms that will require user signatures.
We could retrieve an image of a user's signature and display that on demand in the web page.
Is it possible to be more interactive and allow users to "sign" the form/page within the browser? Are there any 3rd party control libraries that would support this functionality?
I pretty sure this can be done on native applications, but can I achieve this through Asp.Net Core?

I found signature_pad in github, and it works for me.
You can take a look at the screenshots of my test steps first, and I will add the test code at the bottom.
Test Code
1. signature.cshtml
#*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*#
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<form method="POST">
<p>
<canvas width="500" height="400" id="signature"
style="border:1px solid black"></canvas><br>
<button type="button" id="accept"
class="btn btn-primary">
Accept signature
</button>
<button type="submit" id="save"
class="btn btn-primary">
Save
</button><br>
<img width="500" height="400" id="savetarget"
style="border:1px solid black"><br>
<input id="SignatureDataUrl" type="text">
</p>
</form>
<script>
$(function () {
var canvas = document.querySelector('#signature');
var pad = new SignaturePad(canvas);
$('#accept').click(function () {
var data = pad.toDataURL();
$('#savetarget').attr('src', data);
$('#SignatureDataUrl').val(data);
pad.off();
});
$('#save').click(function () {
$.ajax({
url: "/ForTest/get_signature",
type: "POST",
data: { base64png:$('#SignatureDataUrl').val()},
success: function (data) {
console.log("success");
},
error: function (hata, ajaxoptions, throwerror) {
alert("failed");
}
});
});
});
</script>
2. C# code
[HttpPost]
public string get_signature(string base64png) {
var dataUri = base64png;//"data:image/png;base64,iVBORw0K...";
var encodedImage = dataUri.Split(',')[1];
var decodedImage = Convert.FromBase64String(encodedImage);
System.IO.File.WriteAllBytes("signature_pic/"+DateTime.Now.ToString("yyyyMMddHHmmss")+"signature.png", decodedImage);
return "ok";
}
Tips
If you want test my code, you need create signature_pic folder like me.

Related

How to access C# application from jQuery in Razor Pages?

Environment: ASP.NET Core 6.0, Razor Pages
Authentication:
The users log in, and their access token (Bearer jwt) is stored in Session storage.
The problem:
I want to display an array of objects that a request gives me. These objects have a part that has to be queried separately for each of them from the backend. For presentation purposes, I want to display them on the same page, but I do not want to query them before the page loads, because that is slow.
So the question is, how to access HttpClient (or the service that uses HttpClient and handles requests) from jQuery? My current idea is to pass the Bearer token to the partials, that way it can be accessed from them, and to go with an XMLHttpRequest. Are there any better solutions to populate these dropdowns on demand?
Index.cshtml
#page
#model IndexModel
#foreach (var part in Model.Parts)
{
<partial name="_PartPartial" model="new { PartData = part, Id = #Model.Id, Bearer = Bearer }" />
}
Index.cshtml.cs
public class IndexModel : PageModel
{
public List<PartModel> Parts;
public string Id;
public async Task<IActionResult> OnGetAsync(string Id)
{
// Query Parts from endpoint...
return Page();
}
}
_PartPartial.cshtml
#model dynamic
<div class="card">
<div class="card-header">
<button type="button" class="btn" data-bs-toggle="collapse" data-bs-target="#partContent_#Model.PartData.partId"
aria-expanded="false" aria-controls="partContent_#Model.PartData.partId" data-id="#Model.PartData.partId" onclick="queryInnerData(this);">
#Model.PartData.DisplayName
</button>
</div>
<div class="collapse" id="partContent_#Model.PartData.partId">
<div class="card card-body">
<div id="innerData_#Model.PartData.partId"></div>
</div>
</div>
</div>
<script type="text/javascript">
function queryInnerData(sender)
{
// This is the part where I am stuck. How do I access the Bearer
}
</script>
I have tried creating a page that does an HttpRequest and returns a JsonResult in its OnGet method. This works, but exposes the raw data to the outside world as well, so I would rather not go with this solution.

Alpine Expression Error: createFormComponent is not defined

I am using Alpine JS in .NET Core 6 MVC project. I have loaded the alpine js file from https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js. I then added the following code in the Home/Index.cshtml file.
<form id="myForm"
x-data="createFormComponent()"
x-on:submit.prevent="onSubmit">
<input id="email" type="text" name="email"
x-model="email" />
<span class="error" style="display: none"
x-show="error"
x-text="error"
></span>
<button type="submit">Submit</button>
</form>
#section Scripts {
<script>
(function () {
'use strict';
window.createFormComponent = function () {
return {
email: '',
error: '',
onSubmit($event) {
this.error = !this.email
? 'You must enter an email address'
: '';
},
};
};
})();
</script>
}
But when I access the page in the browser, it always throws the error "Alpine Expression Error: createFormComponent is not defined". I have tried to put it into a js file and load it. Also tried to define the component in alpine:init event. None of them worked. The same code works in plain html file served from IIS. I am not sure what is wrong here. Can anyone please help.
Be sure add js in your _Layout.cshtml or in your current page #section Scripts {...} like below:
<script src="https://unpkg.com/alpinejs" defer></script>
Note: HTML defer attribute must be added.

How to turn off the webcam after using Pubnub?

I started to use Pubnub for making video group chats. However, when I was testing it, I found a little problem: As I connect my computer to their servers, my webcam turns on and never turns off, unless I leave the page.
However, I wish to be able to close a video chatting, and turning off the webcam at the same time. How to do it?
Thank you very much!
EDIT: Here is a code I'm using for my tests, I'm using the one given in the tutorial:
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/jquery-ui.min.js"></script>
<script src="js/pubnub-3.7.18.min.js"></script>
<script src="js/webrtc.js"></script>
<script src="js/rtc-controller.js"></script>
<div id="vid-box"></div>
<div id="vid-thumb"></div>
<form name="loginForm" id="login" action="#" onsubmit="return login(this);">
<input type="text" name="username" id="username" placeholder="Pick a username!" />
<input type="submit" name="login_submit" value="Log In">
</form>
<form name="callForm" id="call" action="#" onsubmit="return makeCall(this);">
<input type="text" name="number" placeholder="Enter user to dial!" />
<input type="submit" value="Call"/>
</form>
<div id="inCall"> <!-- Buttons for in call features -->
<button id="end" onclick="end()">End</button> <button id="mute" onclick="mute()">Mute</button> <button id="pause" onclick="pause()">Pause</button>
</div>
<script>
var video_out = document.getElementById("vid-box");
var vid_thumb = document.getElementById("vid-thumb");
function login(form) {
var phone = window.phone = PHONE({
number : form.username.value || "Anonymous", // listen on username line else Anonymous
media : { audio : true, video : true },
publish_key : 'pub-c-c66a9681-5497-424d-b613-e44bbbea45a0',
subscribe_key : 'sub-c-35aca7e0-a55e-11e5-802b-02ee2ddab7fe',
});
var ctrl = window.ctrl = CONTROLLER(phone);
ctrl.ready(function(){
form.username.style.background="#55ff5b"; // Turn input green
form.login_submit.hidden="true"; // Hide login button
ctrl.addLocalStream(vid_thumb); // Place local stream in div
}); // Called when ready to receive call
ctrl.receive(function(session){
session.connected(function(session){ video_out.appendChild(session.video); });
session.ended(function(session) { ctrl.getVideoElement(session.number).remove(); });
});
ctrl.videoToggled(function(session, isEnabled){
ctrl.getVideoElement(session.number).toggle(isEnabled); // Hide video is stream paused
});
ctrl.audioToggled(function(session, isEnabled){
ctrl.getVideoElement(session.number).css("opacity",isEnabled ? 1 : 0.75); // 0.75 opacity is audio muted
});
return false; //prevents form from submitting
}
function makeCall(form){
if (!window.ctrl) alert("Login First!");
else ctrl.dial(form.number.value);
return false;
}
function end(){
ctrl.hangup();
}
function mute(){
var audio = ctrl.toggleAudio();
if (!audio) $("#mute").html("Unmute");
else $("#mute").html("Mute");
}
function pause(){
var video = ctrl.toggleVideo();
if (!video) $('#pause').html('Unpause');
else $('#pause').html('Pause');
}
</script>
Note that I tried to find the function through the console in addition to my searches, but I was unable to find it...

How to use buttons in MVC for different purposes

I do have three buttons in my view. So now I want two buttons to post back and the third button to perform some jquery. How to do this. Like how to make the third button not to post back and perform some jquery actions.
Thanks
You can do this like
<form id="myForm">
<%-- form data inputs here ---%>
<button id="Postback">Postback</button>
<button id="JavaScript">JavaScript</button>
</form>
and in javascript
<script type="text/javascript">
$("#Postback").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("action","MyController")");
form.submit();
});
$("#JavaScript").click(function() {
Do your javascript something.
});
</script>
In HTML the tag button has the attibute type:
To post back data (submit a form) you must set type to submit (this is default value, so you may drop the type attribute at all).
To perform some javascript actions you must set type to button.
In two different submit buttoms use same name and different values:
#using (Html.BeginForm("Login", "Home")
{
<label for="login">Login:</label>
#Html.TextBox("login", Model.Login)
<label for="password">Password:</label>
#Html.Password("password", "")
<button type="submit" name="what" value="login">Log in</button>
<button type="submit" name="what" value="register">Register</button>
<button type="button" id="facebook">Facebook authentication</button>
}
<script>
$(function() {
// Perform jquery action.
$('#facebook').click(...);
});
</script>
In controller:
public ActionResult Login(string login, string password, string what)
{
if (what == "login")
. . .
else if (what == "register")
return RedirectToAction("Register", "Home");
}

ASP.NET MVC4 and Knockout js

I am trying to use knockout js in my project so I tried the simple Hello World example but i couldnt get it to work. I created a new MVC4 project and just copy do a simple binding below is my code
<script src="~/Scripts/knockout-2.1.0.js" type="text/javascript"></script>
<script type="text/javascript">
// Here's my data model
var viewModel = function (first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
//this.fullName = ko.computed(function () {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
//return this.firstName() + " " + this.lastName();
//}, this);
};
$(document).ready(function() {
ko.applyBindings(new viewModel("Planet", "Earth")); // This makes Knockout get to work
});​
</script>
<div class="liveExample">
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
#*<h2>Hello, <span data-bind='text: fullName'> </span>!</h2>*#
</div>
Basically it will just display the value of the model on a textbox.
I already referenced the knockout.js in my project but it does not work
I also added the knockout js in my BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/knockout").Include("~/Scripts/knockout-2.1.0.js"));
I didnt work
If you are using MVC, use the scripts section to declare your JS. This will move the declarations to the bottom of the HTML page, letting the HTML render first. Here's my version of your code that worked first time out of the box:
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div class="liveExample">
<p>First name:
<input data-bind="value: firstName" /></p>
<p>Last name:
<input data-bind="value: lastName" /></p>
#*<h2>Hello, <span data-bind='text: fullName'> </span>!</h2>*#
</div>
#section scripts {
<script src="~/Scripts/knockout-2.2.1.js"></script>
<script type="text/javascript">
var viewModel = function (firstName, lastName) {
this.firstName = ko.observable(firstName);
this.lastName = ko.observable(lastName);
};
$(function () {
ko.applyBindings(new viewModel("Planet", "Earth"));
});
</script>
}
try putting knockout in the of your document. Without any error messages the only thing I can say is I ran into a similar problem and that was the fix for me.
My example was driving me crazy because it worked in fiddle but not in MVC, I mentioned it to a designer friend of mine and he said it made since to him, basically that knockout needed to be fully downloaded before the page began to render.
Hope this helps