Passing Angular data to code-behind function on button click - asp.net

I have a code-behind function that is called when a hyperlink is clicked. The function should then get the name attribute from the hyperlink and use that string to call another function. The name attribute is being populated by an angular ngRepeat. My problem is that when I try to get the name attribute in the code-behind, it just shows an empty string and not the name attribute that "should" have been passed.
HTML
Print Invoice
Final HTML Output
<a data-name="90979157" href="javascript:__doPostBack('ctl00$MainContentPlaceholder$ctl00','')">Print Invoice</a>
VB Code-Behind
Public Sub btnPrintInvoiceClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim inv As HtmlAnchor = CType(sender, HtmlAnchor)
Dim invoiceNumber As String = inv.Name
GetInvoicePDF(invoiceNumber)
End Sub
Thanks in advance!
Edit: Added HTML output

As you can see from the HTML that gets sent to the browser, .NET causes the <a> tag to perform the javascript function __doPostBack('ctl00$MainContentPlaceholder$ctl00','') when it is clicked. This function submits the <form> tag which surrounds the entire contents of your page back to your code-behind class. That code-behind then does special magic with the hidden form elements on your page that .NET webforms put there to identify the state of the page.
This is the classic .NET webforms paradigm, and is a lot more complex than the <a> tag pointing to a url would have you believe. It is also very different from how angularjs is meant to be used. You said in a comment that the data-name value is correctly passed when hard-coded in. This is probably the doing of the __doPostBack function, and it's unsurprising that it does not play well with angular (since its generated per page by code that was written before angular was created). You have two possible options:
Change your <a> tag to an <input type="button" value="{{invoice.DocumentNumber}}" runat="server" ID="yourButton" /> Why would this work? Simply put, you just want angular to transclude the right value into the html so that when webforms submits, the data is passed to your page. Since <a> tags have no relationship to form values, the page rightly ignores its data-name value. In fact I'm surprised that hardcoding the value works at all, because a form post should ignore things that are not form elements. It cannot ignore an <input> element, though.
Change your Public Sub btnPrintInvoiceClicked... method from being a server-side onclick handler to be its own endpoint. Take a look at http://www.asp.net/web-api or its older, web-forms-era cousin: http://www.codeproject.com/Articles/353260/ASP-NET-Advanced-Generic-Handler-ASHX
As an aside, this is the first time I've heard of someone trying to use angular with webforms, the latter being a bit of a dinosaur that Microsoft has hinted at abandoning and the former being in-vogue javascript MVC darling. I know it may not be possible, but you should consider moving to .NET MVC if possible since it is a much better backend environment in which to host your angularjs app.

Related

Header.Stylesheet.CreateStyleRule on partial postback

I've recently added an UpdatePanel to a single webpage which renders different usercontrols on button clicks. I'm struggling with a problem where i'm adding inline styling into the header dynamically with Header.Stylesheet.CreateStyleRule - the problem is that it doesn't get inserted on partial postbacks and it does make sense. This is obviously because it's a partial postback and the header is only being rendered when the page loads the first time.
The styling is being added by the following methods, which gets the styling from a database:
Private Sub InitializeStylesheet(ByVal ButtonId As Integer)
Dim CSSStylesheet As Stylesheet = StyleBackend.GetStylesheets(ButtonId)
Dim IdClassList As List(Of StyleIDClass) = StyleBackend.GetStylesheetsStyleIDClass(CSSStylesheet.StylesheetID)
'Iterates through the cssidclass
For Each cssidClass In IdClassList
Dim styleItems As List(Of StyleItem) = StyleBackend.GetStyleItemsByIDorClass(cssidClass.StyleIDClassID)
Dim cssString As String = Nothing
For Each StyleItem As StyleItem In styleItems
cssString += StyleItem.Property & ":" & StyleItem.Value & ";"
Next
'Iterates all cssitems which belongs to a cssidclass
Me.Header.StyleSheet.CreateStyleRule(New CustomStyle(cssString), Nothing, cssidClass.ClassOrID)
Me.Header.ViewStateMode = UI.ViewStateMode.Disabled
Next
End Sub
I've been googling my ass off trying to get this to work, but it seems to be impossible.
This msdn article literal says that it is impossible to do what i'm trying to do.
http://msdn.microsoft.com/en-us/library/system.web.ui.htmlcontrols.htmlhead.stylesheet.aspx
Adding styles or style rules programmatically during asynchronous postbacks is not supported. When you add AJAX capabilities to an ASP.NET Web page, asynchronous postbacks update regions of the page without updating the whole page. For more information, see Microsoft Ajax Overview.
Does anyone have a suggestion or alternative way of doing this?
Thank you!
One solution is just to include the styles in your main stylesheet(s) rather than modifying them dynamically. Even if they are data-driven, you could output them with the main page via an HTTP handler if the total list isn't too large.
Alternatively (and probably more efficiently), you can return the style data to the client as a string and process it there.
You can listen for the EndRequest event on the client script manager:
function endRequest(){
// look at the updated DOM
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
Perhaps the following sequence:
Initiate async postback
Render the styles to a hidden field inside the UpdatePanel
On endRequest, examine the DOM to see if it contains a hidden field with styles (based on naming convention, data attributes, or just ID)
Grab the values out of the hidden field and add them to the page's style rules using JavaScript

What control to render dynamic HTML text on an aspx page

Page_Load generates a string of HTML for a dashboard. (html)
What control on an aspx page to bind that "text" to so when the page renders you see the tables, and buttons within?
Tried
With dhtml.Text = html but I don't see the buttons. I do see the tables as well as the borders of cells that I expect.
Any ideas?
TIA
You can inject any text/html into your ASPX page using: <% =GetMyText() %> where "GetMyText()" is a public or protected method in your code behind that returns a string.
You can also drop a Literal control onto a form and set the text via its "Text" property.
But if you want to do things the ASP.NET way, you might use a Gridview or Repeater to display tabular/repeating data, and Databind to it with some data.
If you are starting out with ASP.NET, you would probably be better off learning ASP.NET MVC as it is easier to get your head around if you are used to writing HTML. ASP.NET Web Forms, which you are using, generally tries to insulate you from HTML, CSS, and Javascript by giving you controls that you drop onto the page and bind data to. The controls do a lot of work for you, but take away almost all control of your HTML, CSS and Javascript.
I use javascript to dynamically create html elements. Your page_load function could register a javascript function which creates the elements you need.
Not sure why you were downvoted, but a very simple one to use is the HtmlGenericControl.
Basically, just add a span or div to your .aspx file and give it an ID and the runat="server" attribute.
Then, in your code behind just set the InnerHtml property of that control to your generated html.

Rendering of asp.net controls

I find it hard when using asp.net controls, to make proper css files because I don't know what the html output for the different controls end up as.
For example, if I want to add a div tag using a asp.net control, it's not easy to know what kind of control I can use.
Are there any documentation that shows for each asp.net control, what the rendered html for that control will be? I understand that some controls will probably change it's output due to how it's configured, but most controls will at least follow a pattern here.
The best would of course be a service on the web where you can put in the asp.net control definition and get the rendered html out.
Currently I have to put a control into my webform, run it and check the source in the browser, and if it's not the correct html tag, try another control and repeat. That get's tedious quite fast.
If you want to know to what html-controls a server-control is rendered, you could call RenderControl:
Dim myGridView as new GridView
Dim sb as New StringBuilder()
Dim sw as New IO.StringWriter(sb)
Dim textWriter as New HtmlTextWriter(sw)
myGridView.RenderControl(textWriter)
' now we can have a look what asp.net has rendered: '
Dim gridViewHTML as String = sb.ToString()
The rendered html will even differ from browser to browser for example when ASP.Net thinks the client uses a "lower"-browser(BrowserCaps), a Panel will be rendered as Table instead of a DIV.
By the way, if you're testing my above code on controls inside of your page, you have to override VerifyRenderingInServerForm otherwise you get a "...must be placed inside a form tag with runat=server"-error:
Public Overrides Sub VerifyRenderingInServerForm(ByVal control As System.Web.UI.Control)
Return
End Sub
I would recommend adding a CssClass to your WebControls, and doing all your styling using classes, rather than HTML element types. As Tim Schmelter says, the html can render differently for different clients (I seem to remember a Panel can be a span as well under certain circumstances).
To avoid actually having to add the CssClass each time, you can subclass the WebControl you want, then set it's CssClass in Control_Init.

Assign database value to hyperlink but not a runat=server

Its simple if I have an ASP.net page with an ASP.net linkbutton / hyperlink
and I obtain a value from say a SQL Database and I store it in the label...
For example:
this.myLabel.Text = someValueReturnedFromADatabase
This is simple because it goes right to the code behind page and set the text value
to the value returned from my database (aside from going into more details with data access layer, etc).
What I was wondering is what if I dont want to use an ASP.net linkbutton and I simply want to use an HTML link button (as I need to call the jquery fade function). How would I set the value someValueReturnedFromADatabase to a control that is not runat=server?
Have a variable in your codebehind:
protected string TextForLabel
Set it in Page_Load, or wherever:
TextForLabel = someValueReturnedFromADatabase;
Reference it with pointy-bracket percent notation:
<% =TextForLabel %>
You can set runat="server" on standard html controls. I do it all the time. Then you will be able to access their properties in your code behind just like you do for asp controls.
If I am not mistaken, for labels you can use .InnerText or .InnerHTML to change the text.
From what I know of, you need to make some sort of relation between your HTML document and the code behind to interact with data from a SQL database. Either that or you'll have to make the entire database connection etc. in the HTML header using script type="text/javascript" and script type="text/C#" or whatever language you use to develop.

Allowing any property/attribute on a server/usercontrol

I've noticed that on most, if not all, standard web controls in the System.Web.UI.WebControls namespace, you can add any properties you want to them without crashing the page.
Take the asp:Button control for an example.
This code is perfectly valid:
<form runat="server">
<asp:Button runat="server" Text="Test button" crapAttribute="crapValue" />
</form>
Now, I've got a custom server control which crashes if I add arbitrary attributes to it. It only accepts attributes which have a corresponding public property defined.
The error I get is something like this "The control does not have a public property named "crapAttribute" ".
I would like my custom controls to accept any attribute without crashing. What do I need to do for that to work?
I've looked at the standard controls in Reflector and they do have all kinds of attributes and stuff but there was nothing that I saw which immediately caught my eye.
My custom controls are inheriting from WebControl for what it's worth.
You don't have to do anything in particular to allow arbitary attributes to be added the control markup. Things deriving from WebControl would normally scoop up these attributes and dump them in the Attributes collection.
I can't think of reason why this would fail. You would have to remember to render the Attributes collection in your implementation of Render if you have one.
Can you add a simple example of the code of a new control that fails to your question?
One way of doing it is adding the custom property in code behind
myCustomControl.Attributes.Add("customproperty", "value");
This should do the job for you.
However, I am interested in knowing how to do it in the server control itself.

Resources