MVC Razor view make image invisible based on model item condition - html

I have some razor code like:
foreach (var item in projectGroup) {
<tr>
...
<td>
<label id="#( "fieldapprovallabel" + #item.InvoiceLineId)">#item.FieldUserName</label>
#if(item.FieldApproved != null) {
<img src="../../Content/Images/stock_lock.gif" alt="locked" class="lockicon" />
}
</td>
...
}
So basically the lock image is only visible based on a condition. I understand it is not good to have logic like this in the view. Can anyone suggest a better way of doing this?

I don't believe there is anything wrong with simple boolean logic or null checking in the view.
The only alternative would be to hide it all in some helper class that would return the html (or an empty string), which I think adds unnecessary complexity in a simple case like this.

You could create a view model with a property called IsLocked. This abstracts the business logic used to make the "IsLocked" determination, and doesn't state how the view should behave, just informs the view that the item is in a particular state.
The subsequent binding code would be similar, but doesn't require the view to know that item.FieldApproved equals a locked condition.
Of course, in the context of your application item.FieldApproved may already be a clean separation of concerns, in which case I think it's fine as is.

Related

Arbitrarily run method during ngFor loop (Angular 5)

I have an angular page, where, during an *ngFor loop, I want to update a variable, then write it to the HTML during each iteration of the loop.
Like so:
HTML:
<table *ngFor="let data of Dataset">
somehowRunThis(data)
<div>{{methodResult}}</div>
</table>
TS:
...
methodResult: any;
...
somehowRunThis(data): {
let a;
...
this.methodResult = a;
}
etc etc.
Is there any way this can work? Attempting to add a method that returns within the curly brackets seems to not work, and there appears to be no effective way to run arbitrary methods from the HTML in Angular.
Thank you for any assistance you can provide.
Is there any particular reason why you want to trigger this update in HTML?
Depending on your needs you can use pipe (https://angular.io/guide/pipes) or transform the data to desired format in your component.
I would say it's not a good idea to have a method with side-call effects invoked in HTML.
There are a lot of ways to do this. A general advice: sometimes we are looking for an answer in the wrong places, be open :)
Instead of forcing ngFor, just run a simple array.map on your data before sending it to the template.
displayData = this.data.map(el => this.somehowRunThis(el))
this way you'll avoid having terrible performance.
If you don't care and still want to do this thing for some reason you can make your function return it and actually call in template:
{{ myFunctionReturnsText() }}
This is a bad idea because the function calls will run on each change detection so something like Pipes/Directives will be better.

Component selector in variable - Angular 2

I have written my own table module. Calling it in HTML code looks like this:
<my-table [data]="variableWithArr"></my-table>
Now, pretty nice table is being displayed. Cool. But what if I want to have a progress bar in some column of table? I thought that I could put a HTML code with component selector as value, for example bootstrap progressBar, like this:
for(let record of variableWithArr) {
record[0] = '<ngb-progressbar type="danger" [value]="100"></ngb-progressbar>';
}
Unfortunatelly, Angular displays only a HTML code but dooes not interpret it as component selector, so I receive something like that in DOM:
<td><ngb-progressbar type="danger" [value]="100"></ngb-progressbar></td>
How to fix it?
This is not how Angular works - you can't insert arbitrary HTML (innerHTML or otherwise) and expect that directives will be picked up & applied. Making Angular work this way would require shipping entire compiler to a browser and would defeat the whole purpose of all the great optimizations that can be done with the ahead-of-time (AOT) compilation.
tl;dr; nope, you can't do this and this has nothing to do with the ng-bootstrap project, but rather with design decisions behind Angular.
By looking at the docs you need to use the property [innerHTML], but to be clear only use it when you trust the code!!
So should be something like this:
<td [innerHTML]="record"></td>

Simplifying ASP.Net MVC Razor Code

I'm looking for suggestions on how to simplify/optimize a piece of code in one of my view files in my ASP.Net MVC project. The code works, but I'm not sure if I've written it the best way.
Basically, the code is used to display a list of links to documents, with little thumbnails to the left of each link. The main problem, is that there are two different types of documents, and each type has to have it's thumbnail image stored in a different location, this is a project requirement and can't be changed.
I'm currently accomplishing this with the view code shown below.
// Display a link to every document.
foreach (var document in documentList)
{
<a href="#Url.Content("~/Document/DownloadDocument/" +
document.documentid)" target="_blank">
#{
// This will be the root of all the paths.
var path = "~/Document/DisplayImage/";
// If it's a Type 1 document, we need to use a different path.
if (document.documentType == "Type 1") {
path += "Path/To/Image/Folder";
<img id="imageHolder" src="#Url.Content(path)"
onerror="imgError(this);" />
#document.documentname
}
else {
path += "Path/To/Different/Image/Folder";
<img src="#Url.Content(path)" />
#document.documentname
}
}
</a>
<br />
}
Like I said, the code works, but I'm not too happy with how it's written. Does anyone have any suggestions?
When working with MVC, it's best to keep your Views dumb (no logic, simply rendering).
You can accomplish this by using a strongly-typed View and performing all of the logic in the Controller. It looks like you may already be doing this since you have a documentList.
In this case, documentList should be a list of View Model objects that already have the appropriate image path already set on them from the controller.
I would suggest moving the path to your document image into your model. That way you can just display the image from the path in the model and you wouldn't have to put any logic in your view.

Multi-column Headers With Kendo Grid

I don't know what this is called, and I've messed around a lot with the headerTemplate but can't figure out how to produce this look. I need the second row of column names to 'act normally' in terms of sorting and filtering, but everything I try breaks that. I have no idea if headerTemplate is even the right way to do this? Is there a name for this kind of grouping? My research is turning up a whole lot of nothing, so I suspect I'm using the wrong keywords. What is this layout called?
Note: for security reasons I can't post a code dump (super nervous about the image too). If a specific thing is needed, please let me know and I'll try to anonymize it. But, mostly I'm just looking for suggestions to try other than playing with the headerTemplate.
This is now natively supported by the Kendo grid. Here's an example.
You won't be able to achieve multirow Group headers via Kendo grid on MVC, although there were discussion to add the feature in the current version(2014Q2) of Kendo. See below link for more reference:
Pivot Grid StackOverflow Reference
However, you can achieve the multirow header option via jquery on databound event of the grid. But it is a workaround rather than a perfect soultion.
Please see the js function for databound event to add multirow header:
function onDataBound(arg) {
var myElem = document.getElementById('trParentHeader'); //Check if Parent Header Group exist
if (myElem == null){ // if parent Header doesnot exist then add the Parent Header
$("#grid").find("th.k-header").parent().before("<tr id='trParentHeader'> <th colspan='2' class='k-header'><strong>Products + Unit Price</strong></th> <th scope='col' class='k-header'><strong>Single Units in Stock</strong></th></tr>");
}
}
For more understanding and a working example please see below Sample:
MultiRow-Column Header Sample
Please let me know if you if you have any queries.

Simple mechanism to transform dataobjects into HTML in ASP.Net

I am looking for a mechanism to transform dataobjects into HTML. The elements in the dataobject are of both, simple and complex types. I have tried playing with HtmlTextWriter for rendering but got stuck with complex types.
Mine is an ASP.Net website project. I have to avoid using server side controls (and therefore do away with built in binding capabilities) as the front end processing is done with the help of jQuery. I need to just churn out basic HTML for my dataobjects and the rest of enrichment (content arrangement and styling) will be done at the frontend.
I am looking for a simple solution (I found Spring.Net an overkill and overwhelming and NHAML also very confusing).
Further, my application is expected to grow over a period of time so I need to have some respect for performance. Therefore I am avoiding bringing XML/XSLT in the picture.
For eg. A Person object will be something like this:
String: Name
Int: Age
Complex Type: Address (includes Street, City, Zip)
Array of Type "Qualification" : Qualifications (includes Degree, Passing Year, Grades)
Desired output is:
<p id="userName" class="userName">John</p>
<p id="age" class="age">35</p>
<div id="address" class="address">
<p id="street" class="street">Express Highway</p>
<p id="city" class="city">Mumbai</p>
<p id="zip" class="zip">400101</p>
</div>
<div id="qualifications" class="qualifications">
<div id="qualification1" class="qualification">
<p id="degree1" class="degree">B.Sc.</p>
<p id="year1" class="year">1990</p>
<p id="grade1" class="grade">A</p>
</div>
<div id="qualification2" class="qualification">
<p id="degree2" class="degree">M.Sc.</p>
<p id="year2" class="year">1992</p>
<p id="grade2" class="grade">A</p>
</div>
</div>
A point to note here is that a mapper would be required to map the properties from the source dataobject, add some metadata to it (like HTML element attributes, etc) and then carry out the transformation.
I'm looking at it as a design problem and elaborate answer on much higher perspective that is design and not the code! The correct way to do this would be as following.
Person type is holding the information and it is data-centric so I recommend not to put any html-rendering responsibility into this class.
First you will need to have an abstract base-class for all your business/data objects. Let us assume [becuase you'll need to have it] BusinessBase.
So you should start writing a server-control that derives from System.Web.UI.WebContorl. Expose a property that takes an object of type BusinessBase in it's set accessor.
Now you need define some custom Attributes that is applied to properties of any sub-class of type BusinessBase. This attribute holds the renderring output information for that particular property of the business/data object. Decorate all properties which you want to be renderred in html.
Come back to your web-server-control and via use reflection to iterate through all properties [having your custom-attribute] of object which has been assigned to the server control property of type BusinessBase. Render the html as per the attribute.
Now use this web-server-control and business object in your asp.net front-ends. Have fun.
This is a high-level design. You'll need to be more discrete and
specific in your attribute as to what
html rendering is generated for the
business object.
Have you benchmarked XmlSerializer or DataContractSerializer (faster) together with xslt transformations, since you're dismissing them off the bat?
If you still consider xslt to be too slow for your server, let the client render it as xhtml. Then the cpu "burden" is distributed to all your users.
A tutorial can be found at w3schools.com.
It's wise to think about scaling for the future, but you shouldn't dismiss an obvious technology and solution before you actually know it will be the bottleneck.
You should also calculate the cost of adding another front-end server compared to going a more complicated programmatic route. You can also look into caching to improve performance.
[Edit]
Another solution is to implement a WriteHtml method for each class, and from your top class you will call all your child writers. Hand-rolled and effective (but takes more management since you must update the writer if you add a property).
class Person
{
public void WriteHtml(Stream writeStream);
{
writeStream.Write( "<p id="userName" class="userName">{0}</p>", UserName );
etc.
Adress.WriteHtml(writeStream);
writeStream.Write( "<div id="address" class="address">" );
foreach( Address ad in Adresses ) ad.WriteHtml(writeStream);
writeStream.Write( "</div>" );
}
}
You could also override ToString() in each class to return the html representation, and use that instead.
Since you state that classes are simple it should be maintainble and readable, but I still favor xslt, as it's easier to change without recompile. And the most complex render part you ahve is to render your Container tags, since you keep Arrays of objects. If you implemented a Collection class for them, then you could maintain the Container tags in that class instead.
class Person
{
AddressCollection Adresses;
// instead of
Adress[] Adresses;
}
Then the question is, what do you consider "simple" :D