Is it possible to create a property on a javascript object that behaves similar to a property in C#.
Example:
I've created an auto-sizing textarea widget using dojo. In order to get the "value" property out of my widget, I've hooked up to the onchange event and I'm setting a variable everytime the value of the textarea changes.
Is there a way to accomplish this without hooking up to the onchange event.
Edit
In other words, is it possible to write something in JavaScript that behaves like getters and/or setters.
It is possible in ECMAScript 5 implementations, which include recent versions of all major browsers. The ECMAScript 5 spec adds standardized getters and setters. One quirk is that IE 8 has this feature, but only on DOM nodes. This is what the syntax looks like:
var obj = {};
Object.defineProperty(obj, "value", {
get: function () {
return this.val;
},
set: function(val) {
this.val = val;
}
});
There has also been a proprietary implementation of getters and setters in Mozilla for a long time that was also later adopted by WebKit and Opera but this is not available in IE.
I'm not sure what you're asking here. You can always get the value of a textarea without the onchange event. you'd have to get the object then look at the value property.
for example, if your textarea has an id="mytext" you can do
var mytextarea = document.getElementById("mytext");
var text = mytextarea.value;
Related
I'm working on a website that has a JavaScript function I want to call passing in a value when a hyperlink is clicked. I'm generating some table rows in the view like this:
foreach(var e in Model.Collection)
{
...
//This is just an example piece of code that tries to get the big picture
//across. I want to call the JS function below passing in the ShipAddress property
<td>#e.ShippedDate</td>
...
}
And I have a JavaScript function like this:
function popup(data)
{
$('#lblShipAddress').text(data.Address1);
...
// rest of code to fill out labels in a div
$('#divShipInfo').dialog('open');
}
I'm having issues getting the ShipAddress property(which has a number of properties i.e. Address1, Address2, etc.) passed into the JavaScript function from the View. The
href="javascript:popup(#e.ShipAddress)" part doesn't work, and I've also tried using data attributes e.g.
<a href="javascript:popup();" data-shipAddress="#e.ShipAddress" />
but have not had any luck.
EDIT: Added some clarity to what I'm looking for. If at all possible I would like to only pass the ShipAddress property to the function.
By default, just #e.ShipAddress is going to return the equivalent of .ToString(), which is not useful for your method as input. Instead, you'll want to JSON serialize the object like:
#e.ShippedDate
This will result in final html something like:
#e.ShippedDate
And so the popup method would have access to the object values.
Warning: make sure there aren't any fields on your address object that you don't want leaked to your end consumers - Json.Encode will serialize all public properties.
First, I wouldn't use javascript:popup() - try one of these. Also, don't use the quote marks with the razor syntax, or it probably won't evaluate the variable.
If none of that solves it, then it could be a timing issue. I've had a lot of trouble with MVC-controlled pages (as opposed to use JavaScript/jQuery and callbacks) not updating when you think they will. For some reason, the MVC controller deals with the button press, runs the server-side code, updates the page objects... THEN releases control to JavaScript, et. al.
It basically makes using JavaScript with the built-in Microsoft controls almost impossible.
I'm having trouble understanding how to render a collection as a drop down list.
If I have a model like:
public class AccountViewModel {
public string[] Country { get; set; }
}
I would like the string collection to render as a drop down list.
Using the html page helper InputFor doesn't seem to work. It simply render's a text box.
I've noticed that InputFor can reflect on the property type and render html accordingly. (Like a checkbox for a boolean field).
I also notice that FubuPageExtensions has methods for CheckBoxFor and TextBoxFor, but nothing equivalent to DropDownListFor.
I'm probably missing something quite fundamental in understanding html conventions in fubu.
Do I need to build the select tag myself? If so, what is the recommended approach to do it?
You are correct that (at the time I last looked) there is no FubuMVC.Core HTML extension method for generating select tags although you could use the HtmlTags library to generate a select tag via code.
As you touch upon in your question the correct way to attack this is likely with an HTML convention together with the HtmlTags library such as that demonstrated in the FubuMVC.Recipes example 'src/UI/HtmlConventionsWithPageExtensions'.
For example an enum generation example might be:
this.Editors
.If(e => e.Accessor.PropertyType.IsEnum)
.BuildBy(er =>
{
var tag = new HtmlTag("select");
var enumValues = Enum.GetValues(er.Accessor.PropertyType);
foreach (var enumValue in enumValues)
{
tag.Children.Add(new HtmlTag("option").Text(enumValue.ToString()));
}
return tag;
});
The FubuMVC.Recipes repository is quite new and still growing so there may be some better examples around but hope this gives you some ideas.
I'm looking for a way to get the JavaScript code defined inside of onclick.
I'm using .NET 2.0 C# Visual Studio 2005.
Example:
<span id="foo" onclick+"window.location.href='someURL'>click here</span>
My goal is to get the string "window.location.href='someURL'".
Scenario:
A user clicks on web page element, the tag shown above for instance, inside of WebBrowser control. Then the clicked tag is refereed to HtmlElement object.
In WebBrowser control I then call HtmlElement object's getAttribute("onclick"), it just gives me "System.__ComObject".
I've searched how to deal with it then found that it can be casted then get the value.
if (tag.GetAttribute("onclick").Equals("System.__ComObject"))
{
Console.WriteLine("dom elem >>>>>>>>>>> " + tag.DomElement.ToString());
mshtml.HTMLSpanElementClass span = (mshtml.HTMLSpanElementClass)tag.DomElement;
Console.WriteLine("js value ===>" + span.onclick);
}
Output:
dom elem >>>>>>>>>>> mshtml.HTMLSpanElementClass
js value ===> System.__ComObject
As it shown, span.onclick still give me System.__ComObject, what am I doing wrong?
In Why does HtmlElement's GetAttribute() method return “mshtml.HTMLInputElementClass” instead of the attribute's value? this guy said it worked in his case, and I've followed it, but mine is somewhat not working...
UPDATE
Research, research.....
I can add reference VisualBasic.dll to my C# project then call the method to find out who is this System.__ComObject really is.
Console.WriteLine(Microsoft.VisualBasic.Information.TypeName(span.onclick));
Output:
JScriptTypeInfo
It looks like this is a JScript type... how can I access this object?
More detail
The above description is based on my current project. The project is to create something like Selenium IDE. It uses WebBrowser control instead.
Selenium IDE creates 3 different things to record an element in the web document.
1. actionType
2. xpath
3. value
For instance,
type, //input[#id=foo], "hello world"
clickAndWait, //link=login, ""
Selenium IDE recognize page load so it changes actionType between "click" and "clickAndWait". My case, I want to make it simple.
If I click on the element and if it is anchor tag or has page load kind of javascript
such as onclick=window.location.href='blah' then I want to set the actionType to "clickAndWait".
There are number of ways you can do it.
There is an Event object in DOM, which will give you information about which element generated this event.
You can look at here, http://msdn.microsoft.com/en-us/library/ff975965%28v=VS.85%29.aspx
This one is good, you can use this easily, you will get the event object as method parameter which you can investigate parameters to find out the source of the event. http://support.microsoft.com/kb/312777
Another alternative is to use a custom navigation url and act upon it
Override BeforeNavigate event
Check for Navigation url if it contains "mycommand:click" or "mycommand:clickandwait" 3. If it contains any of this, then set cancel as true. (this will stop navigation by browser).
Then you can navigate your webbrowser code from your C# code and pass cancel as true.
Another Alternative method is to use External object, WebBrowser allows you to set an ObjectForScripting which you can access within Javascript of HTML.
ObjectForScripting in .NET 2.0
[ComVisible(true)]
public class MyClass
{
// can be called from JavaScript
public void ShowMessageBox(string msg){
MessageBox.Show(msg);
}
}
myBrowser.ObjectForScripting = new MyClass();
// or you can reuse instance of MyClass
And you can call,
window.external.ShowMessageBox("This was called from JavaScript");
Cast the element object to mshtml.IHTMLDOMNode, then read the attributes via IHTMLDOMNode.attributes. HtmlElement.GetAttribute is getting the IDispatch interface of the jscript function generated from the embedded attribute.
As per Sheng Jiang's response, here is some working sample:
IHTMLElement element = YourCodeToGetElement();
string onclick = string.Empty;
IHTMLDOMNode domNode = element as IHTMLDOMNode;
IHTMLAttributeCollection attrs = domNode.attributes;
foreach (IHTMLDOMAttribute attr in attrs)
{
if (attr.nodeName.Equals("onclick"))
{
string attrValue = attr.nodeValue as string;
if (!string.IsNullOrEmpty(attrValue))
{
onclick = attr.nodeValue;
break;
}
}
}
You can try to parse webBrowser1.DocumentText property using HtmlAgilityPack and then get desired result using XPath.
If you don't HAVE to do it with C# (you can do it with JS and create a Postback) you should take a look at THIS question.
You can parse it yourself easily, by first reading obj.outerHtml. That should give you the entire html for that obj, then search it for the value onclick="????" and extract the ???? part.
I've got a System.Windows.Form.WebBrowser control on a form. I navigate that browser object to a url.
Once the page has finished loading, I'd like to analyse various aspects of the page that loaded.
In particular I'm interested to see the attribute 'writingMode' which is found on the IHTMLStyle3 interface.
Something like:
public void MyMethod(HtmlElement element)
{
IHTMLElement2 element2 = element.DomElement as IHTMLElement2;
IHTMLStyle3 style3 = element2.currentStyle as IHTMLStyle3;
string writingMode = style3.writingMode;
...
The problem is, the style3 value is null. I assume this means IHTMLElement2.currentStyle doesn't support IHTMLStyle3.
I've tried also tried casting IHTMLELement.style. But while that does cast happily as IHTMLStyle3 it doesn't seem to contain the style as it's been applied to the Html element.
Looking at the documentation, I believe you need to get the IHTMLElement2.currentStyle property as the regular style property is the inline style only. This difference is indicated in the remarks for IHTMLElement2.currentStyle:
The values returned by the properties
of the IHTMLStyle and
IHTMLCurrentStyle interfaces differ
when the style of an object is not set
inline. For example, if the author of
a Web page sets the color property of
a paragraph to red only through a
linked or embedded style sheet, and
not inline, then the
IHTMLCurrentStyle::color property
returns the value red, and the
IHTMLStyle::get_color property does
not return a value. However, if the
author specifies the value of the
color property inline, as in the
following example, both the
IHTMLCurrentStyle::color and
IHTMLStyle::get_color properties
return the value red.
currentStyle provides a IHTMLCurrentStyle interface, which when queried for IHTMLCurrentStyle2 will give you writingMode as you require.
I'm an Information Architect and JavaScript developer by trade nowadays, but recently I've been getting back into back-end coding again. And, whilst trying to get an HTML prototype integrated and working with our C#-based CMS, I've come to blows with our programmers over the HTML ID attributes being arbitrarily rewritten by .NET for form elements.
I can understand the code-behind reasoning for .NET changing IDs, but the fact you can no longer use IDs when trying to develop e.g. jQuery enhanced interfaces is causing some friction. What can I do to work around this?
I've tried using the class attribute instead, but that's really crappy, not what it's meant for and doesn't get around that problem of .NET effectively changing rendered source on the fly. It also means that CSS is less useful now and less efficient to create and maintain.
Any tips or advice greatly appreciated--anything for a few less sleepless nights...
The short answer is no, with webforms the id can always be rewritten depending on the nesting of the element. You can get access to the id through the ClientID property, so you could set the ids into variables in a script at the end of the page/control then put them into jQuery.
something like this:
<asp:button id="ImAButton" runat="server">Click Me</asp:button>
<script type="text/javascript">
var buttonId = "<%=ImAButton.ClientId%>";
$("#"+buttonId).bind('click', function() { alert('hi); });
</script>
It's a hack I know, but it will work.
(I should note for the un-initiated, I'm using the Prototype $ get by id method there)
One method is to override the ID's manually:
public override string UniqueID
{
get { return this.ID; }
}
public override string ClientID
{
get { return this.ID; }
}
Rick Strahl wrote a blog post with some more information on that approach.
Look at ASP.Net MVC - it addresses the over-kill object hierarchies that ASP.Net generates by default.
This site is written in MVC (I think) - look at it's structure. Were I working on a new project right now I would consider it first
If you're stuck with basic ASP.Net then be careful overriding the ClientID and UniqueID - it tends to break many web controls.
The best way I've found is to pass the unreadable ClientID out to the Javascript.
You can extend .net controls and make them return actual id's when related properties are called.
ClientID is the id attribute and UniqueID is the name attribute of html elements. So when you create a textbox like the following and using this instead of the textbox in framework, you make id and name attributes render as the same as the server-side id.
public class MyTextBox : TextBox
{
public override string ClientID { get { return ID; } }
public override string UniqueID { get { return ID; } }
}
To use this new user control, basically register this control as you would do for a custom user control (you can do is in web.config so you won't have to do it in all your pages):
<%# Register Assembly="MyLibrary" NameSpace="MyLibrary.WebControls" TagPrefix="MyPrefix" %>
And use it like you would use a text box:
<MyPrefix:MyTextBox ID="sampleTextBox" runat="server" />
Personally, I use a set of methods I have developed for bridging the server-side ASP.NET "magic" (I have yet to use the MS MVC stuff yet) and my client-side code because of the munging of the IDs that happens. Here is just one that may or may not prove useful:
public void RegisterControlClientID(Control control)
{
string variableDeclaration = string.Format("var {0} = \"{1}\";", control.ID, control.ClientID);
ClientScript.RegisterClientScriptBlock(GetType(), control.ID, variableDeclaration, true);
}
So, in your server-side code you simply call this and pass in the instance of a control for which you want to use a friendlier name for. In other words, during design time, you may have a textbox with the ID of "m_SomeTextBox" and you want to be able to write your JavaScript using that same name - you would simply call this method in your server-side code:
RegisterControlClientID(m_SomeTextBox);
And then on the client the following is rendered:
var m_SomeTextBox = "ctl00_m_ContentPlaceHolder_m_SomeTextBox";
That way all of your JavaScript code can be fairly ignorant of what ASP.NET decides to name the variable. Granted, there are some caveats to this, such as when you have multiple instances of a control on a page (because of using multiple instances of user controls that all have an instance of m_SomeTextBox within them, for example), but generally this method may be useful for your most basic needs.
What I usually do is create a general function that receives the name of the field. It adds the usual "asp.net" prefix and returns the object.
var elemPrefix = 'ctl00-ContentPlaceHolder-'; //replace the dashes for underscores
var o = function(name)
{
return document.getElementById(elemPrefix + name)
}
With that you can use this kind of calls in jQuery
$(o('buttonId')).bind('click', function() { alert('hi); });
You definitely don't want to hard-code the asp.net-generated ID into your CSS, because it can change if you rearrange things on your page in such a way that your control tree changes.
You're right that CSS IDs have their place, so I would ignore the suggestions to just use classes.
The various javascript hacks described here are overkill for a small problem. So is inheriting from a class and overriding the ID property. And it's certainly not helpful to suggest switching to MVC when all you want to do is refactor some CSS.
Just have separate divs and spans that you target with CSS. Don't target the ASP.NET controls directly if you want to use IDs.
<div id="DataGridContainer">
<asp:datagrid runat=server id="DataGrid" >
......
<asp:datagrid>
</div>
If you're using jQuery then you have loads of CSS selectors and jQuery custome selectors at your disposal to target elements on your page. So rather than picking out a submit button by it's id, you could do something like:
$('fieldset > input[type="submit"]').click(function() {...});
I can see how the .NET system feels less intuitive, but give it a chance. In my experience it actually ends up creating cleaner code. Sure
<asp:button id="ImAButton" runat="server">Click Me</asp:button>
<script type="text/javascript">
var buttonId = <%=ImAButton.ClientId%>
$(buttonId).bind('click', function() { alert('hi); });
</script>
works fine. But this is suffers from not being modular. What you really want is something like this:
<script type="text/javascript">
function MakeAClick(inid)
{
$(inid).bind('click', function() { alert('hi); });
}
</script>
and then later with your code on the java side or the C# side you call MakeAClick. Of course on the C# side it makes more sense, you just ClientID in there.
Maybe this is the real problem with the code you are reviewing.
A much better approach would be to use the ClientIDMode and set it to static. You can even set it for a specific page or globally in the web.config file. Then you never have to deal with this issue again and your JQuery is much cleaner.
Top of page:
<%# Page Title="" ClientIDMode="Static" Language="C#" CodeBehind="..." Inherits="WebApplication1.WebForm2" %>
On control only:
<asp:Panel runat="server" ClientIDMode="Static"></asp:Panel>