1

I have the following line in my html source:

<input class="phone" name="site_url" type="text" placeholder="Enter Your Website URL">

When I navigate using WebBrowser Control (C#) and load my site to an HtmlDocument object, and then loop over each HtmlElement, when I get to the input element above:

I can't get the placeholder attribute. GetAttribute("placeholder") returns "". I checked the OuterHtml/InnerHtml fields and noted that placeholder attribute is copied with "" while other attributes are not, moreover, I can retrieve other attributes (name, class).

This is the output of InnerHtml/OuterHtml:

<INPUT class=phone placeholder="Enter Your Website URL" name=site_url>

Can anybody explain why is that and how can I change placeholder in this case?

Nizar Blond
  • 1,826
  • 5
  • 20
  • 42
  • What exactly you have in your source (check with view-source): `placeholder="Enter Your Website URL"` or `placeholder=**"**Enter Your Website URL**"**` ? – noseratio Aug 26 '13 at 14:18
  • the first, the ** is for bolding the text (). – Nizar Blond Aug 26 '13 at 14:23
  • I see, I'd suggest editing your question and removing those stars, you cannot use bold inside the code. – noseratio Aug 26 '13 at 14:27
  • reread it now, i think you misunderstood me. ** aren't part of the code. it is exactly how it looks like now. the problem is that only placeholder attribute has double quotes – Nizar Blond Aug 26 '13 at 14:31
  • I meant to remove the stars from the code fragment you originally posted as part of your question. You did just that - awesome, now it's easier for someone to try to help you. – noseratio Aug 26 '13 at 14:35

2 Answers2

2

By default, WebBrowser control runs in IE7 compatibility mode. In that mode, placeholder attribute is not supported. Thus, first you need to switch it into IE10 mode, here's how. Then, you would need to call unmanaged getAttributeNode and get its value, here's how:

bool FindElementWithPlaceholder(HtmlElement root, string placeholder, ref HtmlElement found, ref string value)
{
    foreach (var child in root.Children)
    {
        var childElement = (HtmlElement)child;
        dynamic domElement = childElement.DomElement;
        dynamic attrNode = domElement.getAttributeNode(placeholder);
        if (attrNode != null)
        {
            string v = attrNode.value;
            if (!String.IsNullOrWhiteSpace(v))
            {
                value = v;
                found = childElement;
                return true;
            }
        }
        if (FindElementWithPlaceholder(childElement, placeholder, ref found, ref value))
            return true;
    }
    return false;
}

// ...

HtmlElement element = null;
string value = null;
if (FindElementWithPlaceholder(this.WB.Document.Body, "placeholder", ref element, ref value))
    MessageBox.Show(value);

This code has been tested with IE10.

[EDITED] You can still retrieve the value of placeholder with the above code, even if WebBrowser Feature Control is not emplemented. However, placeholder won't function visually in such case, because the document won't be in HTML5 mode.

[EDITED] Perhaps, I finally understand what you want. Try this code and see if it does that. You still need the Feature Control and DOCTYPE to enable HTML5.

HTML: <!doctype html><html><input class=phone placeholder=\"Enter Your Website URL\" name=site_url></html>

HtmlElement element = null;
string oldValue = null;
string newValue = "New Value";
FindElementWithPlaceholder(this.webBrowser1.Document.Body, "placeholder", ref element, ref value, newValue);

bool FindElementWithPlaceholder(HtmlElement root, string placeholder, ref HtmlElement found, ref string oldValue, string newValue)
{
    foreach (var child in root.Children)
    {
        var childElement = (HtmlElement)child;
        dynamic domElement = childElement.DomElement;
        dynamic attrNode = domElement.getAttributeNode(placeholder);
        if (attrNode != null)
        {
            string v = attrNode.value;
            if (!String.IsNullOrWhiteSpace(v))
            {
                domElement.removeAttributeNode(attrNode);
                domElement.setAttribute(placeholder, newValue);
                // a hack to make IE10 to render the new placeholder  
                var id = domElement.getAttribute("id");
                var uniqueId = Guid.NewGuid().ToString();
                domElement.setAttribute("id", uniqueId);
                var html = domElement.outerHTML;
                domElement.outerHTML = html;
                var newElement = root.Document.GetElementById(uniqueId);
                domElement = newElement.DomElement;
                if (String.IsNullOrEmpty(id))
                    domElement.removeAttribute("id");
                else
                    domElement.setAttribute("id", id);
                found = newElement;
                oldValue = v;
                return true;
            }
        }
        if (FindElementWithPlaceholder(childElement, placeholder, ref found, ref oldValue, newValue))
            return true;
    }
    return false;
}
Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • This prints the value of placholder (e.g. "Enter your WebSite URL") - my whole point is to change it programmatically by SetAttribute and then Invoke a "click" to have my own input instead of "Enter your website URL". How does this answer help me? – Nizar Blond Aug 28 '13 at 13:34
  • Well, perhaps then you should edit the title of your question *HtmlElement doesn't parse the tag properly* and its content *I can't get the placeholder attribute.* Did my answer address that, at least? – noseratio Aug 28 '13 at 14:10
  • That said, if you just add the following `((dynamic)element.DomElement).value = "New Value"` next to `MessageBox`, it will do what you need, if that's the whole point of it. – noseratio Aug 28 '13 at 14:12
1

HtmlElement exposes only those attributes that are common to all elements, leaving out those that only apply to certain types of elements;

HtmlElement.GetAttribute is identical to IHTMLElement::getAttribute(strAttributeName, 0)

There are some change on how getAttribute is working related to Internet Explorer 8, check Remarks section. To resolve this you can do manual parsing for InnerHtml to extract that custom placeholder attribute.

volody
  • 6,946
  • 3
  • 42
  • 54
  • I need to change the text and submit the form. Do you mean to replace strings? if yes, what should I change (InnerHtml? OutHtml? the Body?) so if I call InvokeMember the form will be posted with the new text? – Nizar Blond Aug 26 '13 at 15:18
  • You can use HtmlElement.SetAttribute for that. Find element by name site_url and set attribute value by using el.SetAttribute("placeholder", "new value") – volody Aug 26 '13 at 15:36
  • this will add a new placeholder ignoring the existing. not sure if that's what i want – Nizar Blond Aug 26 '13 at 17:03