I have the following code in a Razor view where I want to only display an address if the first piece is available.
#if (!string.IsNullOrWhiteSpace(Model.Address1))
{
#Model.Address1<br />
#Model.Address2<br />
#Model.City, #Model.State #Model.Zip
}
However, it's giving me a design time error saying "Can not use local variable 'Model' before it is declared".
I've done some searching on the syntax and as far as I can tell it looks correct but obviously I'm missing something. Can anyone see why this would work?
UPDATE
It's a little clunky looking but this is what I ended up with.
#if (!string.IsNullOrWhiteSpace(Model.Address1))
{
#:#Model.Address1<br />
if (!string.IsNullOrWhiteSpace(Model.Address2))
{
#:#Model.Address2<br />
}
#:#Model.City, #Model.State #Model.Zip
}
You're writing HTML which is being parsed as C# code, with confusing results.
The contents of a code block (such as #if) are parsed as code, not HTML.
Therefore, #Model.City, #Model.State #Model.Zip becomes a malformed variable declaration.
You need to wrap it in an HTML tag or <text>, or prefix each line with #:.
Related
Recently, in Blazor 7, a feature has been added to make it easier to bind and call the method based on changes in the bound expression.
In .NET 7, you can now easily run async logic after a binding event has completed using the new #bind:after modifier:
<input #bind="searchText" #bind:after="PerformSearch" />
#code {
string searchText = "";
async Task PerformSearch()
{
// Do something async with searchText
}
}
In this example, the PerformSearch async method runs automatically after any changes to the search text are detected.
Another method has been added too. The #bind:get and #bind:set modifiers are always used together. The #bind:get modifier specifies the value to bind to, and the #bind:set modifier specifies a callback that's called when the value changes.
The questions are:
What is the difference between #bind:after="PerformSearch" and #bind:set="PerformSearch"? Both of these seem to call the PerformSearch after the searchText is changed.
Where is the use of each?
What is the difference between #bind:after="PerformSearch" and #bind:set="PerformSearch"?
You should only use #bind:after="PerformSearch" with #bind="searchText",in which case the bind will set the value of searchText, so you shouldn't also try and set it in PerformSearch.
If you use #bind:set="PerformSearch" then you must set the value of searchText in PerformSearch, and use #bind:get="searchText".
Where is the use of each?
The MS Docs article I think gives a good guide. It all depends on your knowledge level on components.
It's important to understand two points:
This is Razor syntax, not C#.
It's just syntactic sugar: high level functionality, shorthand Razor directives to encapsulate existing functionality.
Also note:
There's been a lot of MS Blazor Team activity on this subject since 7.0 was released. See https://github.com/dotnet/aspnetcore/issues/44957 for details on problems with the way the Razor compiler treats the #bind directives.
There are some updates to the MS Docs on the subject - https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-7.0?view=aspnetcore-7.0#blazor-custom-elements.
Here's my demo page for this answer.
#page "/"
<PageTitle>Index</PageTitle>
<input class="form-control mb-3" type="text" #bind:get="this.Value" #bind:set="ValueSetter" #bind:event="oninput" />
<input class="form-control mb-3" type="text" #bind:get="this.Value" #bind:after="ValueSetter" />
<input class="form-control mb-3" type="text" #bind="this.Value" #bind:after="DoSearch" #bind:event="oninput"/>
<div class="alert alert-info m-2 p-2">
#Value
</div>
<div class="alert alert-primary m-2 p-2">
#message
</div>
#code {
private string? Value;
private string message = "Not Set";
private async Task DoSearch()
{
await Task.Delay(1000);
message= $"Set at {DateTime.Now.ToLongTimeString()}";
}
private void ValueSetter(string __value)
=> this.Value = __value;
private Task SearchSetter(string __value)
{
this.searchText = __value;
return DoSearch();
}
}
Let's look at the actual C# code the Razor compiler builds.
This is the code snippet when just using bind:set=this.ValueSetter:
__builder.AddAttribute(8, "oninput", EventCallback.Factory.CreateBinder(
this,
CompilerServices.RuntimeHelpers.CreateInferredBindSetter(
callback: this.ValueSetter,
value: this.Value
),
this.Value));
This simply calls the setter delegate assigned to set.
This is the code snippet when using :bind=this.Value and #bind:after=DoSearch:
__builder.AddAttribute(14, "oninput", EventCallback.Factory.CreateBinder(
this, CompilerServices.RuntimeHelpers.CreateInferredBindSetter(
callback: __value => {
this.Value = __value;
return RuntimeHelpers.InvokeAsynchronousDelegate(callback: DoSearch);
},
value: this.Value),
this.Value));
It's a little more complicated. The compiler builds the equivalent to this:
Task AnonymousMethod(string __value)
{
this.Value = __value;
return DoSearch()
}
A Note on Development Environment Errors
Depending on your development environment, you will get errors with certain combinations. Some of which at the moment appear to be misleading or totally wrong. They will be fixed shortly.
Quote from Dan Roth: Hi folks. The VS fix for this just missed the window for 17.4.4 but should be addressed in the next VS patch update in February. We apologize for the wait and thank you for your patience!
In Visual Studio.
This is a correct error:
<InputText class="form-control" #bind-Value:get="this.searchText" #bind-Value:set="this.SetSearchText" #bind-Value:after="DoSearch" />
Severity Code Description Project File Line Suppression State
Error (active) RZ10019 Attribute 'bind-Value:after' can not be used with 'bind-Value:set'. Invoke the code in 'bind-Value:after' inside 'bind-Value:set' instead.
While this is bull!
<input class="form-control mb-3" type="text" #bind:get="this.Value" #bind:set="ValueSetter" #bind:event="oninput" />
And while it gives this error compiles and runs!
Severity Code Description Project File Line Suppression State
Error (active) CS1503 Argument 3: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<string>' to 'System.Action<string?>'
And this line:
<input class="form-control mb-3" type="text" #bind:get="this.Value" #bind:after="ValueSetter" />
Compiles but is obviously also total bull.
__builder.AddMarkupContent(9, "\r\n\r\n<input class=\"form-control mb-3\" type=\"text\" #bind:get=\"this.Value\" #bind:after=\"ValueSetter\">\r\n\r\n");
Why is it #bind:get+#bind:set and not just #bind+#bind:set?
Because if you see <input #bind="#val" #bind:set="#MyMethod" /> often, it creates confusion:
It looks as if the #bind:set is what makes it a two-way binding, and that you could make it one-way by removing that. Whereas in fact that would be wrong (you'd still have a two-way binding, just one that behaves differently now).
It looks as if it would be equivalent to write <input value="#val" #bind:set="#MyMethod />, and it almost is, but not quite because the formatting logic would differ. Much better not to create the ambiguity and have one correct solution.
We can avoid the above problems by having a compiler rule that #bind:get and #bind:set must always be used as a pair - you can't just have one of them and not the other (nor can you have them with #bind). So none of the weird cases will arise.
Couldn't you use #bind:set to achieve (in effect) #bind:after, and hence we don't need #bind:after?
Theoretically yes. You could #bind:set to a method that writes to your field and then runs your async logic. However, this is far less obvious for newcomers, and is less convenient in common cases. And it invites mistakes: if you do something async before setting the field, the UI will temporarily revert and generally behave badly. So it's valuable to have #bind:after for convenience and to guide correct usage. We can regard #bind:get/#bind:set as a more advanced case mainly for people implementing bindable components, as it gives them a really clean and safe solution, and such developers are advanced enough to understand that they just shouldn't do async work before calling ValueChanged.
Can you use all three at once, e.g., <input #bind:get="#value" #bind:set="#MyMethod" #bind:after="#DoStuff" />?
Sure, why not? I think that the generated logic should await MyMethod before calling DoStuff, since "after" feels like it means "after all the work involved in calling set". It's an edge case but I can't think of any problems this will cause nor any major increase in implementation cost.
Do other #bind modifiers like #bind:event and #bind:format work with this?
Yes, and that's partly why it's a big improvement over manual value/onchange pairs.
you can refer this link get more idea https://github.com/dotnet/aspnetcore/issues/39837
Here are the codes I have to dynamically create and enhance a page. The similar pattern has been working for many other kinds, such as text field, button, grid-view, etc. But I found it cannot work with a listview.
$(document).bind("pagebeforechange", function route(e, data) {
...
$content = $page.children(":jqmData(role=content)");
var markup = '<ul id="calendarList" data-role="listview"><li>HELLO</li></ul>';
$content.html(markup);
$page.trigger('create');
$.mobile.changePage($page);
});
I would always get an error message like,
Cannot read property 'jQuery16409763167318888009' of undefined
Through debugging using Chrome, I found it always fails on the line of $page.trigger('create');
I found the solution myself. It works fine if I replaced the line,
$page.trigger('create');
with,
$page.page();
$content.find( ":jqmData(role=listview)" ).listview();
However, I still don't understand why. I thought the former was a newer, simpler syntax to replace the latter. A single call of $page.trigger('create'); can enhance the entire page at one shot. Does anyone know the difference of these two?
I face a problem using Grails 2 submitToRemote tag.
The following code is what I use in the controller:
def getProposal = {
def layouts = importService.getLayoutsFor(params.product as int)
render(contentType: "text/xml") {
for (layout in layouts) {
option("${layout}")
}
}
}
and in the GSP:
<g:submitToRemote action="getProposal" update="layouts"
onLoading="showProgress();" onComplete="hideProgress();"
value="Do It" />
<select id="layouts" name="layout" required="">
</select>
Using jquery this results in:
showProgress();;jQuery.ajax({type:'POST',data:jQuery(this).parents('form:first').serialize(), url:'/app/controller/getProposal',success:function(data,textStatus){jQuery('#layouts').html(data);},error:function(XMLHttpRequest,textStatus,errorThrown){},complete:function(XMLHttpRequest,textStatus){hideProgress();}});return false
which not works and returns am error:
Node cannot be inserted at the specified point in the hierarchy
But if I use another render method like:
render(status: 0, text: "<option value='1'>Layout 1</option>")
it works.
In both cases the expected answer is transmitted back.
I did not understand why it will not work with the first nicer method. Could anyone explain what I do wrong?
Thx
Edit:
I noted that if I use render(contentType: "text/text") instead it will work. May be it has something to do, that the xml is not properly formatted (no root node?). But why does it work in Grails 1.3.7?
Grails 1.3.7 had a different default javascript provider (prototype). The jquery ajax call trys to infer the type of the response based on what it receives
Below is my Code:
<ui:repeat var="status" value="#{showUpdatedAction.statusUpdates}">
<h:panelGroup>
#{status.content}
<h:form>
<h:commandLink value="Like" action="#{statusAction.likeStatus(status.id,1)}" />
</h:form>
</h:panelGroup>
<ui:repeat>
#{status.content} shows correct values. When I print id of status using #{status.id}, it also gives correct value. But when I click the command link, value passed is always 0 for status.id.
Can someone tell me why this happens and how can I avoid this?
Thank you.
Edit 1
Interestingly, when instead of passing the parameter in function, I pass it using <f:param>, it works perfectly. Can anyone comment on that?
I think you should try using <c:forEach> instead of <ui:repeat>.
I can't tell you exactly, why status.id is 0 in your case but you can directly pass the whole status object in your EL expression. Like so:
<h:commandAction value="Like" action="#{statusAction.likeStatus(status)}" />
Then in your likeStatus you simply do a int statusId = status.getId() or similar and you have what you want.
As an addition: Using <c:forEach> should actually be just a fallback, because people say you shouldn't mix JSTL with JSF for whatsoever reasons.
Your code in the JSF page is just fine, just checked it... (generated the beans at my side too : showUpdatedAction, statusAction , and a simple class Status)
public void likeStatus(String id,long someVal){
System.out.println(id+"___"+someVal);
}
which prints the ids just fine
id1___1
id4___1
Maybe its something to do with the type of the id or something with your beans?
I am developing a Grails (1.0.4) app where I want to edit a collection of collections on a single page in a grid view. I got it to work quite well depending only on the indexed parameter handling of Spring MVC, except for one thing:
boolean (or, for that matter, Boolean) values in the grid can be set via checkbox, but not unset, i.e. when I check the checkbox and update, the value is set to true, but afterwards when I edit again, uncheck the checkbox and update, it remains true.
This is the GSP code of the checkbox:
<g:checkBox name="tage[${indexTag}].zuweisungen[${indexMitarb}].fixiert" value="${z.fixiert}" />
And this is the HTML that is generated:
<input type="hidden" name="tage[0].zuweisungen[0]._fixiert" />
<input type="checkbox" name="tage[0].zuweisungen[0].fixiert" checked="checked" id="tage[0].zuweisungen[0].fixiert" />
I've found a Grails bug that describes exactly this effect, but it's marked as fixed in 1.0.2, and the problem mechanism described there (underscore in hidden field name is put in the wrong place) is not present in my case.
Any ideas what could be the reason?
This is the solution a guy named Julius Huang proposed on the grails-user mailing list. It's reusable but relies on JavaScript to populate a hidden field with the "false" response for an unchecked checkbox that HTML unfortunately does not send.
I hack GSP to send "false" when
uncheck the box (true -> false) with
custom TagLib.
By default checkBox send nothing when
uncheck, so I use the checkBox as
event handler but send hidden field
instead.
"params" in Controller can handle
"false" -> "true" without any
modification. eg. Everything remain
same in Controller.
The Custom Tag Usage in GSP (sample usedfunc_F is "true"),
<jh:checkBox name="surveyList[${i}].usedfunc_F" value="${survey.usedfunc_F}"></jh:checkBox>
Here is what the Tag generate,
<input type="hidden" name="surveyList[#{i}].usedfunc_F" id="surveyList[#{i}].usedfunc_F" value="false" />
<input type="checkbox" onclick="jhtoggle('surveyList[#{i}].usedfunc_F')" checked="checked" />
The Javascript
<script type="text/javascript">
function jhtoggle(obj) {
var jht = document.getElementById(obj);
jht.value = (jht.value !='true' ? 'true' : 'false');
}
</script>
This is my own solution, basically a workaround that manually does what the grails data binding should be doing (but doesn't):
Map<String,String> checkboxes = params.findAll{def i = it.key.endsWith("._fixiert")} // all checkboxes
checkboxes.each{
String key = it.key.substring(0, it.key.indexOf("._fixiert"))
int tagIdx = Integer.parseInt(key.substring(key.indexOf('[')+1, key.indexOf(']')))
int zuwIdx = Integer.parseInt(key.substring(key.lastIndexOf('[')+1, key.lastIndexOf(']')))
if(params.get(key+".fixiert"))
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = true
}
else
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = false
}
}
Works, requires no change in grails itself, but isn't reusable (probably could be made so with some extra work).
I think that the simplest workaround would be to attach a debugger and see why Grails is failing to populate the value. Considering Grails is open source you'll be able to access the source code and once you figure out the solution for it you can patch your version.
I have also found this other bug GRAILS-2861 which mentions the issue related to binding to booleans (see Marc's comment in the thread). I guess that is exactly the problem you are describing.
I would create a small sample app that demonstrates the problem and attach it to the Grails bug (or create a new one). Someone here may be able to debug your sample app or you'll have shown the bug isn't really fixed.
Try this out, set the logs to DEBUG, frist try the first 3 if they don't show the problem up, flip them all to DEBUG:
codehaus.groovy.grails.web.servlet="error" // controllers
codehaus.groovy.grails.web.pages="error" // GSP
codehaus.groovy.grails.web.sitemesh="error" // layouts
codehaus.groovy.grails."web.mapping.filter"="error" // URL mapping
codehaus.groovy.grails."web.mapping"="error" // URL mapping
codehaus.groovy.grails.commons="info" // core / classloading
codehaus.groovy.grails.plugins="error" // plugins
codehaus.groovy.grails.orm.hibernate="error" // hibernate integration
This should allow you to see exactly when and how the parameters setting is failing and probably figure out a work around.