JS in blazor component - javascript

I am trying create an alert message in within a Blazor component. I have no idea how to do this. I am running ASP.NET Core 3.1 Blazor server-side. Here's what I've tried
Component function:
private async Task ShowAlert()
{
await JSRuntime.InvokeAsync<object>("ShowMsg");
}
Javascript Interop:
function ShowMsg() {
success = "Success!";
return success;
}
File host.cshtml:
<script src="~/BlazorInterop.js"></script>

#page "/"
<button #onclick="MessageBox">Show Message</button>
#code
{
[Inject] IJSRuntime JSRuntime { get; set; }
protected async Task MessageBox()
{
await JSRuntime.InvokeVoidAsync("exampleJsFunctions.ShowMsg",
"Hello Blazor");
}
}
Put the following script tag beneath <script src="_framework/blazor.server.js"></script> in the _Host.cshtml file, like this:
<script src="_framework/blazor.server.js"></script>
<script>
window.exampleJsFunctions =
{
ShowMsg: function (message) {
window.alert(message);
}
};
</script>

Related

Maui сhange navigation in BlazorWebView

How can I change a page in BlazorWebView using Maui? For example, the page '/' was opened and I need to open '/fetch'.
I found how to return to the previous link via js.
Created a Custom Navigation Manager:
public class CustomNavigationManager
{
private static IJSRuntime JSRuntime { get; set; }
public CustomNavigationManager(IJSRuntime jSRuntime)
{
JSRuntime = jSRuntime;
}
public static async Task Navigation(string url)
{
//Microsoft.Maui.Platform;
if (JSRuntime!= null)
{
await JSRuntime.InvokeVoidAsync("navigation", url);
}
}
}
Which calls the Js code. Which calls the Js code. Which I placed in wwwroot/index.html
<script type="text/javascript">
window.navigation = (url) => {
window.location.href = url; // Error: There is no content at fetch.
//history.back();
//window.location="https://0.0.0.0/fetch"; //Error: There is no content at fetch.
}
</script>
Registering a service
builder.Services.AddTransient<CustomNavigationManager>();
And inject in Shared/MainLayout.razor
#page "/"
#inject CustomNavigationManager navigation
And I use it in maui
await CustomNavigationManager.Navigation("/fetch");
If I use the js code history.back(); then everything works,
but if I want to redirect to /fetch using
window.location.href = url;
then I get an error: There is no content at fetch.
Fetch.razor page
#page "/fetch"
#page "/fetch/{id}"
<h1>Test!</h1>
Fetch.razor
#page "/fetch"
#page "/fetch/{text}"
<h3>#Text</h3>
#code
{
[Parameter]
public string Text { get; set; }
}
MainLayout.razor
#inherits LayoutComponentBase
#inject CustomNavigationManager navigation
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
About
</div>
<article class="content px-4">
#Body
</article>
<div>#Url</div>
</main>
</div>
#code
{
[Inject]
private NavigationManager MyNavigationManager { get; set; }
private string Url;
protected override void OnInitialized()
{
base.OnInitialized();
MyNavigationManager.LocationChanged += OnLocationChanges;
Url = MyNavigationManager.Uri;
}
private void OnLocationChanges(object sender, LocationChangedEventArgs e)
{
Url = e.Location;
StateHasChanged();
}
}
CustomNavigationManager.cs
public class CustomNavigationManager
{
private static NavigationManager _navigationManager;
public CustomNavigationManager(NavigationManager MyNavigationManager)
{
_navigationManager = MyNavigationManager;
}
public static void Navigation(string url)
{
if (_navigationManager!=null)
{
_navigationManager.NavigateTo(url);
}
}
}
Decided so: Subscribed to the navigation change event. Implemented the service, and called NavigateTo. It didn't work through Js. Note: BlazorWebView must already download the project, otherwise nothing will work)

How to access Spring Boot model with Vue?

I am not sure how to access a model I create with my controller with Vue in my html. I know how to access model attributes with thymeleaf, but cannot find any info anywhere on how to access them with Vue. I would like to store the count value from the controller in the Vue data count I have below. I am using Vue within my template hosted with CDN, not as a separate project.
Here is my controller:
#PostMapping("/word")
public String searchSentence(#ModelAttribute WordSearch wordSearch, Model model) {
int c = wordSearch.search();
String count = String.valueOf(c);
model.addAttribute("wordSearch", wordSearch);
model.addAttribute("count", count);
return "count";
}
Here is the count.html:
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Count-Form</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<h1>Result</h1>
<p th:text="'sentence: ' + ${wordSearch.sentence}" />
<p th:text="'word: ' + ${wordSearch.word}" />
<!--<p th:text="'count: ' + ${count}" /> -->
<div id="count-text" style="display: none">
<p th:text="${count}" />
</div>
<div id="app">
{{count}}
</div>
<script>
new Vue({
el: '#app',
data() {
return {
count: ""
}
},
created() {
this.count = ???
}
})
</script>
Submit another message
</body>
</html>
You can follow this blog to do what you desire. https://dev.to/brunodrugowick/spring-boot-vue-js-axios-and-thymeleaf-with-bootstrap-in-4-commits-2b0l. In this author explains how you can use Thymeleaf and VueJS together by adding VueJS dependency in pom.xml.
you need following dependency in your pom xml to use VueJS,
<dependency>
<groupId>org.webjars</groupId>
<artifactId>vue</artifactId>
<version>2.6.11</version>
</dependency>
Thymeleaf is a server-side Java template engine, while Vue is a JS framework to build frontend layer. The best way to connect Spring with Vue would be by an API.
So you'll need to expose your data as a JSON, make a http call vue app -> java api and consume the response.
Here you can find more details, how this works
All you have to do is create a method returning ResponseBody, then you call this method in Vue (Axios is a good option!).
Example 1: function to get a String variable:
#GetMapping( "/getLanguage")
#ResponseBody
public String obtenerIdiomaActual() {
return languageService.getLanguage();
}
Then you'd need a method in your Vue app to read this value:
const vm = Vue.createApp({
data() {
return {
language: null,
}
},
methods: {
getLanguage() {
axios.get(window.location.origin + '/getLanguage')
.then(response => {
this.language = response.data;
})
.catch(error => {
this.errorMessage = error.message;
console.error("There was an error!", error);
});
},
mounted: function () {
this.getLanguage();
},
watch: {
idioma: function () {
console.log("Language: " + this.language);
}
},
}).mount('#myApp')
You can use all kind of complex data: objects, arrays, dictionaries (maps)...
#GetMapping( "/getComplexData")
#ResponseBody
public Map<String, List<SpaceBean>> getMyComplexData() ...
And read the response easily with Vue:
<div v-for="(spaceList, key) in datos">
<p v-cloak><b>{{key}}</b></p>
<table class="display" style="width: 100%" v-cloak>
<tbody>
<tr v-for="space in spaceList">
<td>{{space.alias}}</td>
<td>{{space.descripcion}}</td>
<td>{{space.url}}</td>
</tr>
...
I hope this help a little!!

Not able to display the raw contents of a file with Spring Boot REST API, Thymeleaf and JS fetch

I have a Spring Boot application which on load of Home page (http://localhost:8080) displays all the filenames within a specific directory on the browser successfully without any issues.
Now, I would like to make those filenames a hyperlink, clicking on which would display the content of that file on the browser.
I am getting a JS error when I do so. The request is not even reaching to the server. Is there something wrong with the way I am calling the function and passing filename parameter in it?
Error:
VM164:1 Uncaught ReferenceError: database.properties is not defined
at <anonymous>:1:17
HomeController.java
#Controller
public class HomeController {
#GetMapping({"", "/", "/home"})
public String index(Model model) {
return "home";
}
}
DirListController.java
#RestController
public class DirListController {
#Autowired
private SshConnService sshConnService;
#GetMapping("/api/dir")
public List<String> showAllDirs(Model model) throws Exception {
return sshConnService.listAllFiles(); //returns [database.properties, messaging.properties, ....]
}
}
RawFileContentController.java
#RestController
public class RawFileContentController {
#Autowired
private SshConnService sshConnService;
#GetMapping("/api/rawFileContent")
public String showRawFileContent(#RequestParam(value = "filename") String filename) throws Exception {
return sshConnService.catFile(filename);
}
}
home.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Directory List</title>
</head>
<body>
<h1>Directory List</h1>
<table id="categoryTable" class="table" style="margin-top:10px;">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<h2>File Contents</h2>
<table id="contentTable" class="table" style="margin-top:10px;">
<thead>
<tr>
<th>File Content</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script src="/webjars/jquery/3.0.0/jquery.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
js/main.js
$(document).ready(function () {
viewAllDirs();
});
/*** Show all files within a directory **/
async function viewAllDirs() {
$('#categoryTable tbody').empty();
const dirResponse = await dirService.findAll();
const dirJson = dirResponse.json();
dirJson.then(filename => {
filename.forEach(filename => {
console.log(filename);
//make the filename clickable and display it's content onclick
let categoryRow = `$(<tr><td>${filename}</td></tr>)`;
$('#categoryTable tbody').append(categoryRow);
});
});
}
const dirService = {
findAll: async () => {
return await fetch('/api/dir');
}
};
/*** View File Contents **/
async function viewFileContent(filename) {
$('#contentTable tbody').empty();
const rawFileContentResponse = await rawFileContentService.findByFilename(filename);
const rawFileContentResponseJson = rawFileContentResponse.json();
console.log(rawFileContentResponseJson);
let contentRow = `$(<tr><td>${rawFileContentResponseJson}</td></tr>)`;
$('#contentTable tbody').append(contentRow);
}
const rawFileContentService = {
findByFilename: async (filename) => {
return await fetch('/api/rawFileContent?filename=' + filename);
}
};
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>5.8.2</version>
</dependency>

Reuse Vue.js stored into the DB

I'm trying to build a simple website builder that allow users to save their generated html created with Vue component and see it at a certain URL.
Because of it I have to store and retrieve the html generated but I have some problems with retrieving of the code. Here is my step:
When user click "save" this function is fired, that select the portion of HTML that include the "website" built by the user:
saveBuilders: function () {
let pages = [];
let builders = $('[id*="builder-container-"]');
$.each(builders, function (key, builder) {
let singleElem = $(builder).attr('id');
pages.push(clearElement.html());
});
this.storeInDb(pages);
},
storeInDb: function (pagesList) {
axios.post("/landing-page/store", {
name: this.name,
description: this.description,
html: pagesList
})
.then(function (response) {
console.log('Cool');
})
.catch(function (error) {
console.log('ERROR', error.response);
});
},
The Axios request is handled by this function that store the html portion in DB
public function store(Request $request)
{
$data = $request->all();
$html = $data['html'];
$landingPage = new LandingPage();
$landingPage->name = $data['name'];
$landingPage->description = $data['description'];
$landingPage->user_id = Auth::user()->id;
$landingPage->html = json_encode($html);
try {
$landingPage->save();
return 'true';
} catch (exception $e) {
return $e;
}
}
Now when the user visit a certain URL, for keep thing simple suppose is example.it/website/0, this function is fired:
public function show($landing_id)
{
try {
$landingPage = LandingPage::where([
'id' => $landing_id,
'user_id' => Auth::user()->id
])->first();
} catch (\Exception $e) {
$landingPage = null;
}
if ($landingPage != null) {
//GET THE HTML
$page = json_decode($landingPage->html);
return view('landing_page.show')->with('page', $page)
} else {
abort(404, 'Error');
}
}
And this the blade where I'm trying to re-create the Vue.js environment
<body>
<span id="countdown"></span>
<div id="builder-pagina">
<builder>
{!! $page !!}}
</builder>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="{{asset('js/landing_page/app.js')}}"></script>
</body>
</html>
I thought that having the html generated by vue similar to something like that into the DB...
<div data-v-29b64d26="" >
<h1>This piece of code was stored into my DB</h1>
<div data-v-56f62f0a="">
</div>
</div>
...you could create everything working simply by pasting the code and by using the same js file used for compiling vue.js.
I've tried pass the entire code by props but is not working. Also tried with slot. Any suggestions?

get a view page using jquery in mvc4

Hi I am working with mvc4
I have a razor view page for the action
public ActionResult DeliveryAddress(string userid,int productid)
{
....
return View(m);
}
that contain
<div >DELIVER HERE</div>
when clicking on this i am collecting somedata ifrom this page using jquery,
$(document).ready(function () {
$("#place-order").click(function () {
var userid = $('#selected-userId').html();
var productid = $('#selected-productId').html();
$.get("Products/PlaceOrder/"+ userid, function (data) { });
});
});
and i want to pen another view of action
[HttpGet]
public ActionResult PlaceOrder(int uid)
{
return View();
}
and paste the variable content,
but $.get("Products/PlaceOrder", function (data) { }); is not hitting this action..
please help me.
This is how you need to pass a data to a url in Jquery get method, note the same parameter name is used in the function
$.get('#Url.Action("PlaceOrder","Products")', { uid: userid }, function (data)
{
});
Make sure your URL is correct. Most probably use #Url.Action(). and also pass the parameter using new as shown below.
$.get('#Url.Action("PlaceOrder","Products",new { userid = #userid , productid = #productid })', function (data) {
});
While collecting the data make sure your parameter names are same for both while sending and while receiving.
[HttpGet]
public ActionResult PlaceOrder(int userid, int productid )
{
return View();
}
Just add HTTPGET attribute in your action method as below.
[HttpGet]
public ActionResult PlaceOrder()
{
return View();
}
java script
$("#place-order").click(function () {
var userid = $('#selected-userId').html(); // $('#selected-userId').val();
$.get('#Url.Action("PlaceOrder","Products", new { uid = userid })', function (data) { });
var productid = $('#selected-productId').html();
});
When I want my view code to be fetched like that, or even through the Html.Action() call, I use the PartialView and normally set my Controller Action as:
public ActionResult PlaceOrder(int uid)
{
return PartialView(new TestViewModel() { ID = uid });
}
as an example:
TestViewModel
public class TestViewModel
{
public int ID { get; set; }
}
PlaceOrder.cshtml
#model TestViewModel
<h2>Partial View</h2>
<p>
Partial View paragraph with the id <b>#Model.ID</b>
</p>
Index.html
<hr />
#Html.Action("PartialView", "Home", new { id = 44 })
<hr />
<div class="ap"></div>
<script>
var url = '#Url.Action("PartialView", "Home")';
$.get(url, { id: 54 }, function (data) {
$(".ap").append(data);
});
</script>
result:

Categories