Vue + Asp.net rendering issue - asp.net-mvc

I have a new asp.net mvc project (not .net core) and I am trying to incorporate Vue js into the project. I have everything working in a sample project using Webpack+Vue+Asp.Net Mvc, which was created following this article https://medium.com/corebuild-software/vue-js-and-net-mvc-b5cede228626.
The app works great, except for the split second before Vue renders. There is noticable flashing/popping of the Vue templated code before its rendered to html. Below is a gif of me refreshing the page and users are able to see the template before Vue renders it into html.
I know why this is happening, but I do not know any ways around it. Would Server Side Rendering fix this? Can SSR be done in a non .net core project?
Unfortunately, switching to asp.net core is not an option. The project will be using Umbraco 7, which cannot run on asp.net core (https://our.umbraco.com/forum/using-umbraco-and-getting-started/93640-net-core).
Below are my files
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<div class="jumbotron">
<h1>ASP.NET</h1>
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
<p>Learn more »</p>
</div>
<div id="app" controller-data="{ name: 'James' }">
<h3>Test</h3>
{{ vueMessage }}
{{ controllerData }}
<first-component v-bind:time="new Date()" data="#Model"></first-component>
<button v-on:click="test">Test</button>
</div>
<div class="row">
<div class="col-md-4">
<h2>Getting started</h2>
<p>
ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
enables a clean separation of concerns and gives you full control over markup
for enjoyable, agile development.
</p>
<p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301865">Learn more »</a></p>
</div>
<div class="col-md-4">
<h2>Get more libraries</h2>
<p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
<p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301866">Learn more »</a></p>
</div>
<div class="col-md-4">
<h2>Web Hosting</h2>
<p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
<p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more »</a></p>
</div>
</div>
#Scripts.Render("~/Scripts/bundle/home.js")
index.js (gets compiled to Scripts/bundle/home.js by webpack)
import Vue from 'vue';
import FirstComponent from './sub-components/first-component.vue'
new Vue({
el: '#app',
components: {
FirstComponent
},
props: {
controllerData: Object
},
methods: {
test: function () {
console.log(this);
}
},
data: function () {
return {
vueMessage: 'Message from Vue'
};
}
})
first-component.vue
<template>
<div class="time">
{{ time }}
{{ data }}
</div>
</template>
<script>
export default {
props: {
time: {
type: Object,
required: true,
},
data: Object
}
}
</script>
<style>
.time {
color: #F44336;
}
</style>

Make use of the v-cloak attribute.
<div id="app" v-cloak>
...
</div>
The attribute is automatically removed by vue when the framework has finished mounting.
The v-cloack attribute does not show or hide your elements - it is basically a marker that indicates if mounting is finished. You write a css selector to target v-cloack to hide the elements or show a loading indicatior.
<style>
[v-cloak] > * { display:none }
[v-cloak]::before { content: "Please wait…" }
</style>

Switching to .net core or any other server side technology would not help.
The issue is because the html is rendered by the browser as it downloads & before all the script resources have downloaded/parsed/run & rendered the html from the Vue component.
When dealing with mixed rendering (partially server side & partially client side) your best option is to hide the template by default & "show" it once the vue component is setup & ready.
For example in your server side view, hide <div id="app"> either with an attribute, style or class.
<style>#app.loading {display:none;}</style>
<div id="app" v-bind:class="{ loading: !isloaded }">
Then in your vue component mounted method set isLoaded to true. This is just one of many ways to hide the component before it's ready.

Related

Dropzone fileupload not working in asp.net MVC (VB.net)

My project is asp.net MVC with VB.net. I am trying add feature of drag and drop a file. I have browsed several websites, also downloaded a code which is in C#. C# code works well. However, code in my project doesn't work. I've compared generated HTML code and they are same. Also tried by moving .css files into "/content" folder manually, adding link to .js manually in .vbhtml page [rather than script.render()]. But it didn't work. I'd tried with other JQuery file upload objects too. But none of them works. So, I thought perhaps the issue is with JQuery. So, I uninstalled it and installed it back. However, it didnt'help too. I am using JQuery 3.3.1.
Can you help ?
Main problem : Nothing happens when I drop the file. e.g. if I drop TXT file, browser just opens the TXT file as if I've dropped it in empty browser window.
HTML code is below :
<div class="row">
<div class="col-md-9">
<div id="dropzone">
<form action="/Home/Upload" class="dropzone needsclick dz-clickable" id="uploader">
<div class="dz-message needsclick">
<textarea rows="10" cols="20"></textarea>
Drop files here or click to upload.<br>
</div>
</form>
</div>
</div>
</div>
JS code is below. I can see alert "bingo" on page load.
#section scripts
<script>
$(document).ready(function () {
alert("bingo!");
Dropzone.options.uploader = {
paramName: "file",
maxFilesize: 2,
accept: function (file, done) {
if (file.name == "test.jpg") {
alert("Can't upload a test file.");
}
else {
//Show a confirm alert and display the image on the page.
alert("bingo2!");
}
}
};
});
</script>
end section

Mobile browser time inputs don't work inside vue element

I have a laravel webapp that uses multiple forms. I have recently introduced Vue.js v2 to deal with some specific custom input types which are working well.
Problem is that ordinary html5 input[type=time] inputs that are inside the vue instance element are not rendered properly in iOS safari/chrome - they appear as native timepickers but appear to have a blank value. When you click to change they do display the correct value.
I can workaround by using a custom vue component that just passes the value property into the vue instance but I figure I must be doing something wrong because I can't find a single mention of this anywhere.
I have managed to reproduce this on JSFiddle problem only appears in mobile browsers
html
<div id="app" style="background-color:lightblue; padding:30px">
<h3>This div is the Vue element</h3>
<form action="">
<p>
<label for="">Standard Input</label>
<input type="time" value="23:24:00" />
</p>
<p>
<label for="">Vue Component</label>
<vue-time value="13:45:00"></vue-time>
</p>
</form>
</div>
<div style="background-color:lightyellow; padding:30px">
<h3>This div is outside the Vue instance</h3>
<form action="">
<label for="">Standard Input</label>
<input type="time" value="23:24:00" />
</form>
</div>
js
Vue.component('vue-time', {
template: '<input type="time" :value="value">',
data() {
return {
value: ''
}
}
});
const vue = new Vue({
el: '#app',
data() {
return {
value: ''
}
}
});
I had a somewhat similar problem and I found this thread that helped me, see if it helps you:
https://forum.vuejs.org/t/solved-fixed-position-element-disappears-during-transition-on-mobile-browsers/8960
I would comment on your question instead of proposing this as an answer but I don't have the reputation to do so yet.

Asp.net MVC button does not show

I place a button in a div tag, and when I run it, I only see the div container
<div style= "border-style:solid;border-width:1px; padding:5px; background-color:#ffffcc">
<asp:button ID = "refresh" runat ="server" OnClientClick="reloadPage()">
<script type="text/javascript">
function reloadPage(){
window.location.reload()
}
</script>
</asp:button>
</div>
the refresh button is nowhere can be found. Are there anything wrong with my code? I am new to MVC, please give me suggestions.
Why are you using asp controls in an MVC project -> use an HTML element.
Use a Form
<div>
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
<button type="submit">Submit</button>
}
</div>
Use a Button
<div>
<button onclick="DoSomeJavascript" >Submit</button>
</div>
MVC uses Controllers (Code Behind) and Views (Html) to create pages. To send data to or from a page you need to use View Models.
Maybe have a look at this handy guide: http://www.asp.net/mvc/overview/getting-started/introduction/getting-started
Your question states that you are new to MVC, yet you are trying to define a button from classic ASP.NET, which will not be processed by the Razor view engine used by MVC. Since you are just reloading the page you can do this with regular HTML buttons and Javascript. I'm not reloading the page here in this snippet, but that's irrelevant.
<div style="border-style:solid; border-width:1px; padding: 5px; background-color:#ffffcc">
<button id="refresh" onclick="reloadPage()">
Refresh Page
<script type="text/javascript">
function reloadPage() {
console.log("Reloaded")
//Reload page here
}
</script>
</button>
</div>
If you run this and click you should see the log message in your Javascript console.

$.mobile.silentScroll does not work in worklight app

I am developing an application using worklight framework from IBM in which I use jquery mobile library to code.
Unfortunately, when I use $.mobile.silentScroll to scroll, it has no effect, it does not work.
Has anyone met that issue? In other work, How to scroll page in worklight?
I don't think you can do this with jQuery Mobile's silentScroll, as it basically uses window.scrollTo, and this allows to scroll only within the current viewport (what you currently see on the screen).
Instead I would recommend to use iScroll's various API methods: scrollTo, ScrollToElement or Snap, etc.
I tested the below in Android and it worked.
You'll of course need to adjust it to your application...
common\js\main.js:
var myScroll;
function wlCommonInit(){
myScroll = new IScroll('#wrapper');
}
common\index.html:
<body style="display: none;">
<div id="wrapper">
<div data-role="page" id="page">
<div data-role="content" id="content" style="padding: 15px">
<div id="firstDiv">
<input type="button" value="scroll to the other div" onclick="myScroll.scrollToElement('#secondDiv', '0s');"/>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div id="secondDiv">
hello
</div>
</div>
</div>
</div>
...
...
</body>
0s means there will be no scroll effect; it will essentially 'jump' to the desired location.

bootstrap - no scrollbars on IOS?

I am using bootstrap version 2.x and when i use the app on a non mobile browser the scrollbars work correctly, however when i browse using iOS (iphone 5) there are no scrollbars -- specially vertical scrollbars and i cannot touch scroll on the screen - its just fixed i cannot more left or right or up or down......
Is there something i need to enable for touch scrolling like a different js library? or is there something broken.
I have read that if the tags for are not closed properly this could occur but my tags are closed.
So basically all my content is now not visible except for the first portion as i cannot scroll down...
Here is some code ( i am using durandal as a SPA)
this is my shell:
<div>
<header>
<!--ko compose: {view: 'nav'} --><!--/ko-->
</header>
<section id="content" class="main container-fluid">
<!--ko compose: {model: router.activeItem,
afterCompose: router.afterCompose,
transition: 'entrance'} -->
<!--/ko-->
</section>
<footer>
<!--ko compose: {view: 'footer'} --><!--/ko-->
</footer>
</div>
at the moment i removed all 'nav' and 'footer' rendering and only something in the content HTML that is rendered in there a simple page:
<section>
<div>
<button id="btnrefresh" class="btn btn-info btn-force-refresh pull-right"><i class="icon-refresh"></i> Refresh</button>
<button id="btnrefresh2" data-bind="click: refresh" class="btn btn-info btn-force-refresh pull-right"><i class="icon-refresh"></i> Data Refresh</button>
<h3 class="page-title" data-bind="text: title" ></h3>
<div data-bind="visible: showDetails" style="height:500px;width:50px;background-color:red">
</div>
</div>
</section>
this will not scroll in IOS :(
The answer to this was that it as a Durandal based problem.
After severe debugging and stripping everything out except durandal i figured out this can be fixed by opening up durandal/app.js and commenting out the following lines of code:
adaptToDevice: function() {
//document.ontouchmove = function (event) {
// event.preventDefault();
//};
}
Cheers

Resources