How can I make code indentation behave correctly in vbhtml razor files? - asp.net-mvc

This is driving me round the bend. I'm a long time VB.NET forms developer, quite new to ASP.NET and completely new to MVC. I'm creating vbhtml pages that use the VB.NET Razor syntax, and I seem to be constantly fighting against the UI which is trying to indent my code incorrectly. Take the following example, based on the template page for a new Razor view:
#Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
#If True Then
#<ul>
#For x = 1 To 2
Next
</ul>
End If '<-- Randomly indented too far
</div>
</body>
</html>
In the above example, as soon as I hit return after Next, End If two lines below randomly jumps two tabs forward from where it should be. In other examples I've hit a circle where pushing one line to the correct place throws another line out of position and vice versa.
I'm so annoyed at this point I'd be happy to disable auto-indentation completely and just manage it myself, but I can't even find out how to do that! Following advice on another thread I disabled indentation for HTML pages but all that stops is indentation of HTML tags - the code blocks still slide around all over the place.
I thought an extension might be causing the problem but I disabled them all and restarted and the problem remains. Am I doing something fundamentally wrong? I find it hard to believe Microsoft would release something so poor so it seems more likely I'm just not using it right.

I found a solution (of a fashion) on another question (I really did search hard before posting this question and couldn't find anything): Why doesn't Visual Studio code formatting work properly for Razor markup?
Essentially the solution seems to be to ensure that your code uses spaces instead of tabs for the whitespace. Whilst increasing the overall size of the page because of increased whitespace, it does lessen the problem (whilst not eliminating it completely). On the linked thread, someone who appears to be connected with Microsoft has acknowledged it is indeed a bug related to the overlapping formatters for HTML and VB.NET which they hope to improve in a new release. I've dropped to 2 spaces per indent to lessen the bandwidth impact.
Thanks to the guys who contributed.

A better alternative here(rather than using spaces for tabs), is to change the block indenting for HTML and C#/VB to "Block" instead of "Smart". This isn't a full solution, but IMO is a far less painful work-around than using spaces!

Related

grails fields plugin <f:display is 'chopping off' bootstrap dropright action with a table of values

grails v 3.3.9, fields plugin
fighting with fields plgin and theres a problem when rendering domain objects and using bootstrap
i've got a sample here from a simple standalone page to show the problem
<p>f:display category </p>
<f:display bean="maintenanceAgreement" >
</f:display>
<hr />
<p>f:field category</p>
<f:field bean="${this.pageScope.maintenanceAgreement}" property="category">
<g:render template="/_fields/map/displayWidget" ></g:render>
</f:field>
<hr />
in essenence i have added a template in "/_fields/map/displayWidget" that renders a drop right table on a button
when you render a map field directly from your Domain object the sample table opens and you get all of the table
however when you
you can see the differences between using f.display (has clipping problem), f.field ( which seems to work) and f.all that ignores my _fields/map/_displayWidget.gsp
I dont want to have not use the fields plugin but its not working with bootstrap templating
has any one come up with a fix for this problem?
the project demo page is here
github standalone page to show rendering problem
the attached shows the output as you try each and select category property
well goldarn it another 2 days down the pan - but i have it !
I thought at first it was something to do with fields plugin processing. so i hacked a clone of plugin project locally and added some bits so i could watch it/debug step through it
in doing so i noted that my dummy web domain class page i'd cut across to the plugin didnt have the clipping problem. but the styles were not the same so i copied main.css and grails.css from ordinary project back into the plugin, then re rendered in the browser - and the clipping happened again.
so its in the css!. some very careful watching of browser and looking at the browser 'inspect' indicated that the clipping seemed to be enabled very early on in the journey.
so in my dummy page i just used
I then spent a day wandering round the various bits of fields plugin as its not that well explained anywhere.
if you look at the plugins taglib display method, by default that triggers the /templates/fields/_list.gsp. naming is a little odd but its the gsp that renders the domains persistent attributes as an ordered list - the plugins default _list.gsp looks like this
<ol class="property-list ${domainClass.decapitalizedName}">
<g:each in="${domainProperties}" var="p">
<li class="fieldcontain">
<span id="${p.name}-label" class="property-label"><g:message code="${domainClass.decapitalizedName}.${p.name}.label" default="${p.defaultLabel}" /></span>
<div class="property-value" aria-labelledby="${p.name}-label">${body(p)}</div>
</li>
</g:each>
</ol>
so after much exploration coming up through templates, from the bottom I ended up right at the top with the '
so nearly there now. back into main.css that i'd copied in. if you edit that, down around line 215 you get this style. If you comment out the overflow property - its all fixed !
.property-list .fieldcontain {
list-style: none;
/*overflow: hidden; */
zoom: 1;
}
I tried auto, scroll, and visible but that seems to much about with too much of the page so best to just comment it out.
once you do that - the rest of the rendering of your forms starts to work !! blimey one line of css for all that pain. Attached is the page using
Lastly through out all this, id ended up digging through /tracing fields plugin. What a nest that is. Not really finished here, but basically
with no body just renders a label and no content. So you either need to provide provide a body tag, say to get the value field displayed.
as
if no widget template has been defined then the renderDefaultDisplay is called which again has very limited options for controlling the rendering by falling through a 'switch (prop.type)' and basically calls either g.format (bool), g.formatDate (but no LocalDateTime/LocalDate Support) or g.fieldValue, non of which are bootstrap enabled.
if you call
these two diagrams are not beautiful but just high level pseudo code walk through for what the core tags are trying to do. One day i'll try and pretty that up but it might help you if you get stuck
I'll raise a bug for the main.css clipping directly to the grails team and see what happens, but you can comment the line out yourself if you fall foul of it.

Chrome unresponsive during loop in MVC view

I have a view that simply populates the page with objects from a list in my model, but during this, Google Chrome becomes unresponsive and asks whether we want to kill the pages. This is a bit frustrating as IE and FF both work fine (loads instantaneously) and I am not about to start recommending users use IE as a short-term solution (just can't bring myself to do it).
Here is an example of where the page is dying. The loop is populating rows in a table:
For i = 0 To Model.ListOfStuff.Count - 1
#<tr>
<td>#Html.LabelFor(Function(d) d.ListOfStuff(i).SelectedItem, Model.ListOfStuff(i).Name)</td>
<td>
#Html.CheckBoxFor(Function(c) c.ListOfStuff(i).SelectedItem)
#Html.HiddenFor(Function(c) c.ListOfStuff(i).Id)
</td>
</tr>
Next
This contains no more than 900 records, so I'm not sure why Chrome is falling over at this.
So my question to SO, is, how do I optimise this so that Chrome does not fall over? OR, is there a known work around for Chrome becoming unresponsive? I'm clutching at straws here.
Many thanks for any help.
In case anyone stumbles across this and is in a similar position, here is the solution to the problem.
The problem was that I was including jquery-1.7.1.js in my shared _Layout.vbhtml view, in a bundle. For some reason, although no jQuery was actively being called, this caused multiple views to crash if they included loops with quite a few records in them.
To fix this, I created a new shared layout view called "_LayoutNoScripts.vbhtml" (and removed all scripts) and set the problematic view's Layout to this instead:
#Code
Layout = "~/Views/Shared/_LayoutNoScripts.vbhtml"
#End Code
Then, because jQuery was actually needed in the view, I included the script as an individual reference:
<script src="#Url.Content("~/scripts/jquery-1.7.1.js")"></script>

String.format help needed with mvc 3 razor (vb.net) please?

I've inherited some code... and am trying to convert it to use MVC 3, with Razor, the VBHTML is as follows:
For Each Message As MessageDetailsModel In Model.Messages
#<div id='#Message.HeaderId' class='#Message.HeaderCss' onclick=#(String.Format("shMsgTree('{0}','{1}',{2},'{3}');", Message.HeaderCss, Message.HeaderId, Message.MessageId, Message.UserId))>
... more stuff...
</div>
Next
Stepping through the code, the String.format resolves to this:
shMsgTree('sh_msg_GridItem sh_msg_MessageRead ','divHeader0',40,'{85A433F0-4054-42E7-B778-3EF005E411D3}');
which is what I want on the page, but for some reason, it gets output on the page as this:
shMsgTree('sh_msg_GridAltItem" sh_msg_MessageRead="
The properties on the model are all strings.
Am at a bit of a loss as to how to get it to render. Originally the entire onclick javascript was being returned in the Model, but that didn't render any better either.
Any suggestions would really be welcome. Thanks!
Given our conversation in the comments and the fact that the original Razor is quite hard to read, I think I'd recommend either:
writing a Razor Helper for this small block of code http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
or writing a normal Extension Method to output the code - http://weblogs.asp.net/jgalloway/archive/2011/03/23/comparing-mvc-3-helpers-using-extension-methods-and-declarative-razor-helper.aspx (this is what I would choose!)
Without stepping through it in code, it's too hard to read the syntax as currently written - so break it out into a separate compact, testable, readable component.
Hope that helps
Stuart
Not sure if this will do it, but your onClickcode needs to be wrapped in quotes, before and after: onClick="#(String.Format(...))"

Why doesn't Visual Studio code formatting work properly for Razor markup?

Or, should I rather ask, when will VS code formatting work properly for Razor markup? The formatting works for most structures, but it seems to choke on 'if' blocks. The code below is as it is formatted by VS. It is very easy to fix this case, with one more indent, but I nicely accepted the formatting in everyday use, and like to use it often for the bulk of my code, so I'd rather avoid manual formatting if possible. Right now I just leave it as VS formats it.
#{
if (User.Identity.IsAuthenticated)
{
<text>Hello </text>
#Html.Display("#ViewBag.UserName") <text> - </text>
#Html.ActionLink("Sign Out", "LogOff", "Account", null, new { style = "font-weight: bold;" })
}
}
I think it's important for readability that, e.g. in the above, the body of the if block is indented, besides just looking nicer.
Be sure to set the editor to use space characters and not tabs. The editor seems to completely lose its mind when tabs are used. This is a shame because all those space characters end up in the actual HTML output, greatly increasing the data transfer size.
What I do is manually supplement the automatic formatting as I type. Not ideal, but hopefully Microsoft will have this figured out for the next service pack.
I found one "solution" that allows you to continue using tab indentation and have correct formatting. It's more of a pattern. The key is to use razor code blocks instead of inline code.
So for example, replace the following:
<div>
<div>
#if (true)
{
<b>Hi</b>
}
</div>
</div>
with:
<div>
<div>
#{
if (true)
{
<b>Hi</b>
}
}
</div>
</div>
The latter will format correctly, but the former won't.
Keep in mind, the formatting isn't perfect, but it's better than before.
It does not work correctly in all cases because it's a difficult problem to solve. Essentially you have 3 different editors (HTML, C#, and Razor) all interacting over the same text buffer. There are some cases (like this one) where the interactions have bugs. But we are working on improving the editor for the next release of Razor.
A better alternative here(rather than using spaces for tabs), is to change the block indenting for HTML and C#/VB to "Block" instead of "Smart". This isn't a full solution, but IMO is a far less painful work-around than using spaces!
In my case it was resharper overriding formatting options.
If your using reshaper and getting this issue try this...
Resharper >> Options >> Razor >> Editor & Formatting >> Untick “Auto-format on enter”
I found another solution for this. Just select all code in file, click Shift + tab to remove all tabs before code, copy and paste it. Visual studio automatically format code. Work on VS 2013 .cshtml file
I know it's not really the answer you're looking for but I've used WriteLiteral to get around my formatting issues.
For example, when I write:
<div>
#foreach (var item in Model) {
if (condition) {
#:</div><div>
}
#item.Label
}
</div>
Visual Studio tries to change it to:
<div>
#foreach (var item in Model) {
if (condition) {
#:
</div><div>
}
#item.Label
}
</div>
Which causes the page to throw an error.
If you use WriteLiteral you can fool the formatter into ignoring the line but it ain't pretty:
<div>
#foreach (var item in Model) {
if (condition) {
WriteLiteral("</div><div>");
}
#item.Label
}
</div>
Right now I'm on VS2013 ASP.NET MVC 5 and I still have that problem. What I found to be a lot helpful is to put the first expression on the same line where the opening block symbol is (#{). That way razor code formatting produces a far better result. Here are the before and after cases:
BEFORE
AFTER
I work with VS2017 15.9.2 and still have the problem.
After change the editor settings to use spaces instead of tabs, the behavior in editing (e.g. copy - paste code lines) is way better, but "Format Document" still add wrong indents by every call.
No solution, but a short update:
It seems as the issue is solved partial in Visual Studio 2019 version 16.0 Preview 2.1
Link to MS for the issue
Further short update:
I have found a (bad and ugly) workaround (to write the whole code to a razor control in ONE line.
You can find the details here Workaround to wrong indentation Razor Controls
You might want to try Improvements to the new Razor editor in Visual Studio - it has greatly improved the formatting quality (still imperfect, though).
I recommend you prevent automatic formatting to trigger by commenting the piece of code where you paste. This way things don't get broken on paste.

Rendering complete page and not "progressively" (using struts 2 / tiles)

Is there a way to get struts 2 (using tiles) to build the whole page before sending it to the browser? I don't want the page to be build "progressively" in the browser one part at a time.
The main problem I'm trying to solve is that internet explorer 7 flashes/blinks the page even if only some of the content changes (firefox does this much more smoothly).
So that if I have a page with:
HEADER
some content
FOOTER
And the "some content" area only changes between page loads, the FOOTER part still flashes the white background before filling it with the background color of the footer. I tought that maybe by getting struts to send the complete page it would load fast enough to eliminate the "blinking".
Now the FOOTER comes from the server a little bit later than the parts before it and so it flashes (in internet explorer, firefox displays the page smoothly).
NB: this is an important requirement for the site, and using ajax to load the middle content is out (as are frames or other "hacks"). The site is built using CSS and not a table layout, maybe I will have to use a table layout to get it to work...
About using tiles flush parameter:
I tried that and it doesn't work as I need. I would need a flush-parameter for the whole page. I have tried the normal jsp page directive "autoFlush=false" but it didn't work. I set this directive on my main template page (and not in the tiles).
Here is an example from the main template, which uses header, body and footer templates. With the Thread.sleep() I added the problem is easy to spot. The footer renders 2 secs later than the rest of the page.
<body>
<div id="container">
<t:insertAttribute name="header" flush="false" />
<div id="content"><t:insertAttribute name="body" flush="false"/></div>
<div class="clear"></div>
<% Thread.sleep(2000); %>
<t:insertAttribute name="footer" flush="false" />
</div>
</body>
UPDATE
Thanks for the comments. The requirement is actually almost reasonable as this isn't a normal web page, think embedded.
But apparently there is no way of configuring IE to start rendering after some delay (like firefox has a configurable delay of some 100ms)?
I tried to intercept the TilesResult but the method doExecute is run before the whole content is apparently evaluated, so the method has already exited before the jsp is evaluated (my Thread.sleep() test). I was wondering how I could render the whole response to a string and then output that all at once to the browser.
I know that this isn't foolproof and network delays etc may factor in this, but if I could get the response to output all at once and maybe use a table based layout (IE possibly renders the table only after the table closes) this could work reasonably.
Or then try to get this switched to firefox or maybe forget all about this little glitch...
UPDATE 2
This started to bother me so I did some investigation.
If I had a plain jsp page (no tiles) the buffering works (with the buffer attribute), so that if I had my Thread.sleep() there the whole page rendered after two seconds if the page size was below the buffer size.
But if I used tiles in the page (as in the example above) I couldn't get the page to render at the same time (I even included the page directive in all my tiles-templates/"components", no help). So tiles probably flushes the response somewhere?
Furthermore, the "problematic tiles" was my body-part, which contained a struts:form tag. I replaced it with a normal form-tag and it worked as I wanted...
UPDATE 3
Ok, nobody seems to know the inner workings of tiles or struts tags...
No big problem as this is a very specific case and requirement.
I worked around it by using apache as a proxt in front of the application, and using apache's proxy configuration options to specify a large buffer.
I'll mark this as answered.
You can send page data all at once at the server end if you like (and many frameworks do that anyway for convenience) but the reality of networking is that it won't all arrive at once and the browser will render it as packets arrive. And this is a good thing for responsiveness, even if you* aesthetically would like the page to display all at once.
You can reduce the lag as much as possible by simplifying markup and using deflate compression to keep the payload size down, and that's a worthwhile thing to do in general. Plus you can make sure you're not hitting a Flash Of Unstyled Content. But you can't control when the browser chooses to render, short of doing it all in JavaScript with all the downsides that entails (and even then, the browser might redraw slowly).
(* - or your client/boss, if that's who has come up with this "important requirement" that your site somehow work differently to every other page on the web.)
Can you use the "flush" attribute on the tiles components?
<tiles:insertAttribute name="body" flush="false"/>
In addition if the output buffer gets too big, it will flush anyway. Try increasing the buffer size?
<%# page language="java" buffer="500kb" autoFlush="false" %>

Resources