Simple mechanism to transform dataobjects into HTML in ASP.Net - html

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

Related

Issues with text rendering in react component

So I am working with an API, and found this in the documentation:
let message = {
"text" : "<i>or</i> HN: the Next Iteration<p>I get the impression that with Arc being released a lot of people who never had time for HN before are suddenly dropping in more often. (PG: what are the numbers on this? I'm envisioning a spike.)<p>Not to say that isn't great, but I'm wary of Diggification. Between links comparing programming to sex and a flurry of gratuitous, ostentatious adjectives in the headlines it's a bit concerning.<p>80% of the stuff that makes the front page is still pretty awesome, but what's in place to keep the signal/noise ratio high? Does the HN model still work as the community scales? What's in store for (++ HN)?",
"time" : 1203647620
}
So in react (using function component), what is the proper way of rendering message.text? I am asking because my rendering output still has the tag <i></i> and <p></p> in the text when I return {message.text}. So I guess there is something wrong.
If you want to render a string containing html you can use dangerouslySetInnerHTML
In your case will be:
<div dangerouslySetInnerHTML={{ __html: message.text }} />
Watch out using this attribute because it could expose your app to XSS attacks. (check https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml)

Create reusable block of vue template within creating new component

In some instances, I need to just repeat some html code within my Template to DRY it up, but making a new component and passing a ton of props and dynamic data to it seems like overkill. Is there a way to define a repeatable block of template code that can just be reused?
A good example of this is my vuelidate validation error messages that are repeated. I don't want to create an entire vue component for them because then I need to pass in the validation, validation prop and a few other things so that seems like creating more complexity just to DRY up a little bit of the template.
I have this block of code on three different scenarious in the same template, is there a way I can just define them as a block to reuse. Literally nothing changes so it's very much against DRY principles.
<span
v-if="!$v.initialReplyText.required"
class="error">Your reply cannot be empty.</span>
<span
v-if="!$v.initialReplyText.maxLength"
class="error">Your reply cannot be over 2,000 characters.</span>
you can do dynamic binding using v-bind, that way you don't need to bind all properties individually.
<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>
src: https://v2.vuejs.org/v2/api/#v-bind
You can also use slots, or scoped slots, which are commonly used for things like wrapping error messages in more complex markup.
If all elements are consecutively arranged as in your example, you can use v-for as below:
<span v-for="(criteria, msg) in {'Your reply cannot be empty.': !$v.initialReplyText.required, 'Your reply cannot be over 2,000 characters.': !$v.initialReplyText.maxLength }"
v-if="criteria" class="error">
{{msg}}
</span>

Idiomatic way of passing both event and local vue variable to bound function

I was trying to figure out how to access both a v-for member and the original event data to a bound function on an event in vue.js, but couldn't for the life of me find it in the documentation.
What I want:
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="locationChanged">
with locationChanged calling the following method in my vue object:
vuePickup = new Vue({
el: '#pickups',
data: {
pickups: pickups,
},
methods: {
locationChanged: (event, pickup) => {
pickup.newLocation = event.target.value == -1;
}
},
});
which requires access to both the element in question and the object that was bound to that portion of the v-model.
By default, using v-on:change="locationChanged" calls locationChanged with the event, and the element can be reached via event.target but I couldn't find a way to access the pickup object I was binding the particular element to.
Using v-on:change="locationChanged(pickup)" instead causes locationChanged to be called with the model I need, but I then lose the reference to the HTML element in question.
What I ended up doing was setting up a local function in the model itself to forward the values:
v-on:change="e => locationChanged(e, pickup)"
which provides me with the information I need.
However, I feel that this is not the correct approach as a) I couldn't find it in the documentation, and b) it's not the most user friendly.
#Lawless pointed me to an existing question by another user who was wondering more generally how to access the event (as compared to my goal of accessing the event target, i.e. the element that triggered the event), but my question about the idiomatic approach here remains as this is a very basic question (callbacks for enumerated elements) and yet both solutions (mine and the linked question) are not very obvious and not covered in the vue.js manual.
Is there a more idiomatic approach prefered by the vue.js community?
Another question on StackOverflow (pointed out to me by #Lawless) was asking the same question I started off with (namely, how to access the event data in a binding for an enumerated element rather than one associated with a top-level vue.js object), providing another, more direct (but imho even more arcane) approach to accomplishing the same.
To recap, starting with an HTML element generated by vue.js bound to a vuejs object obtained via enumeration
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="locationChanged">
...
</select>
</div>
How do you access both the backing object (here, pickup) and a reference to the select element so you can query its new value and act accordingly.
My approach was to take advantage of the fact that vuejs passes in the event by default and work around the fact that vuejs suppresses the event parameter if you explicitly provide a local object as the parameter in the callback by using a lambda:
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="e => locationChanged(e, pickup)">
...
</select>
</div>
Explicitly adding the element I'm interested in to the callback, at the cost of an extra function call/layer of indirection.
The previous answer provided a solution that takes advantage of the explicitly defined vuejs $event variable, which is always translated to the native browser event, which can be directly used in addition to whatever other variables you wish to capture, making the solution look like this:
<div class="card pickup" v-for="pickup in pickups">
<select v-on:change="locationChanged($event, pickup)">
...
</select>
</div>
Which requires more intimate knowledge of vuejs, but avoids the closure.
However, I kept searching because it did not feel like this solution was in line with the vuejs ethos (and all I ever heard was everyone raving about how awesome the vuejs docs are, but this answer wasn't explicitly there but rather had to be pieced together).
It seems that I was grappling with a common case of knowing what I want but not how to get there.. and my previous domain knowledge that precluded vuejs led me to the non-idiomatic approach in my question rather than how I would have solved it if I started off learning frontend development with vue.js in the first place.
In the end, I found the obvious answer I was looking for, an answer that felt like it was the correct "vuejs way" of doing it and the proper idiomatic solution to my original question:
The problem is that I was intermingling standard JS/DOM introspection with the vuejs model, and the friction arose in the transition between the two (leaky abstractions and all). I wanted a native handle to the select element along with a vuejs object (pickup), when what I should have been doing was using vuejs exclusively to accomplish what I needed, ultimately by binding the select element to a vuejs object/property, and referencing that directly in my bound callback:
<div class="card pickup" v-for="pickup in pickups">
<select v-model:pickup.location v-on:change="locationChanged(pickup)">
...
</select>
</div>
With the select element now bound to the location property of my vuejs model, I can directly query its state/value in my locationChanged handler and pass in my pickup object without needing to use either $event or a closure:
let vuePickup = new Vue({
el: '#pickups',
data: {
pickups: pickups,
},
methods: {
locationChanged: (pickup) => {
pickup.newLocation = pickup.location == -1;
}
},
});

MVC Razor view make image invisible based on model item condition

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.

GWT Widget from HTML

I have a block of HTML that I would like to use as the basis of a GWT widget, but am not quite sure the best way to do so. As an example, my HTML block looks something like this:
<div class="my-widget">
<div class="header">
<span class="title">Title Text</span>
</div>
<div class="body">
<span class="content">Content Text</span>
</div>
</div>
Now, I can of course paste this as a static string into an HTML widget, but in this case I need the ability to set the text of the "title" and "content" elements on the fly. This kills (or at least makes significantly more difficult) the static text option.
The first thing that comes to mind in that case is to build out the elements in GWT manually and hold references to the ones I need to alter, like so:
DivElement container = document.createDivElement();
setStyleName(container, "my-widget");
setElement(container);
DivElement header = document.createDivElement();
setStyleName(header, "header");
container.appendChild(header);
// Hold onto this element for later manipulation
DivElement title = document.createDivElement();
setStyleName(title, "title");
header.appendChild(title);
But this quickly get unmanageable for all but the simplest of layouts (which mine is not.)
What I would like is the ability to send the HTML in as static text and then do some sort of selector, like jQuery, to query the elements I want to manipulate. I'm aware of GWT-Query but I haven't been able to get it to run without error, and it seems to me to be a bit too early in it's lifespan for me to be comfortable integrating it into a professional product just yet.
I'm also aware of Google's UiBinder, which sounds exactly like what I want. The problem there is, as far as I can tell, that functionality is only available in GWT 2.0, which is still in a release candidate state and therefore unusable for me.
So, given all that (sorry for the long question!) do you have any suggestions about how best to achieve something like this?
GWT 2.0 will be out before the end of the year. So unless you need to deliver in a few days time, I would start working with the RC2 and try out the new UIBinder approach.
How about using HTML.wrap(). For example, if you added an id of "my-widget" to your outer-most div you could then do something like:
HTML myWidget = HTML.wrap(RootPanel.get("my-widget").getElement());
You can use the InlineHTML widget to produce a span and control its content.
As you probably know, GWT doesn't provide a built in widget that maps directly to a span element. If you can use a div for the title and content, then this bit of code should (no GWT on this machine, going a bit by memory) generate the DOM structure you have.
FlowPanel myWidget = new FlowPanel();
myWidget.setStyleName("my-widget");
SimplePanel header = new SimplePanel();
header.setStyleName("header");
Label title = new Label(titleText);
title.setStyleName("title");
header.add(title);
myWidget.add(header);
SimplePanel body = new SimplePanel();
body.setStyleName("body");
Label content = new Label(contentText);
content.setStyleName("content");
body.add(content);
myWidget.add(body);
From here, you can provide accessors to the content and title labels and update them as needed.
title.setText(newTitle);
content.setText(newContent);
The same as above, but getting a GWT Panel (be able to append childs). This is also useful when you need to wrapp a 3rd party toolkit GUI object as a GWT widget:
Panel gwtPanel = HTMLPanel.wrap(anElement);
The following code suites for me:
HorizontalPanel divContainer = new HorizontalPanel ();
Element div = DOM.createDiv();
div.appendChild(...); // whatever element it could fit inside
divContainer.getElement().appendChild(div);
Edit
The idea behind this is manipulating the DOM with the other widgets you have already programmed.
PS: I'm using GWT 2.4