Skip to content

Commit 303ab72

Browse files
committed
Add the ability to specify the HTML tag the component should be rendered to.
1 parent 067b847 commit 303ab72

File tree

4 files changed

+64
-18
lines changed

4 files changed

+64
-18
lines changed

src/React.Tests/Core/ReactComponentTest.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,25 @@ public void RenderHtmlShouldWrapComponentInDiv()
6363
Assert.AreEqual(@"<div id=""container"">[HTML]</div>", result);
6464
}
6565

66+
[Test]
67+
public void RenderHtmlShouldWrapComponentInCustomElement()
68+
{
69+
var config = new Mock<IReactSiteConfiguration>();
70+
var environment = new Mock<IReactEnvironment>();
71+
environment.Setup(x => x.Execute<bool>("typeof Foo !== 'undefined'")).Returns(true);
72+
environment.Setup(x => x.Execute<string>(@"React.renderToString(Foo({""hello"":""World""}))"))
73+
.Returns("[HTML]");
74+
75+
var component = new ReactComponent(environment.Object, config.Object, "Foo", "container")
76+
{
77+
Props = new { hello = "World" },
78+
ContainerTag = "span"
79+
};
80+
var result = component.RenderHtml();
81+
82+
Assert.AreEqual(@"<span id=""container"">[HTML]</span>", result);
83+
}
84+
6685
[Test]
6786
public void RenderJavaScriptShouldCallRenderComponent()
6887
{

src/React.Web.Mvc4/HtmlHelperExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,20 @@ private static IReactEnvironment Environment
3535
/// <param name="htmlHelper">HTML helper</param>
3636
/// <param name="componentName">Name of the component</param>
3737
/// <param name="props">Props to initialise the component with</param>
38+
/// <param name="htmlTag">HTML tag to wrap the component in. Defaults to &lt;div&gt;</param>
3839
/// <returns>The component's HTML</returns>
3940
public static IHtmlString React<T>(
4041
this HtmlHelper htmlHelper,
4142
string componentName,
42-
T props
43+
T props,
44+
string htmlTag = null
4345
)
4446
{
4547
var reactComponent = Environment.CreateComponent(componentName, props);
48+
if (!string.IsNullOrEmpty(htmlTag))
49+
{
50+
reactComponent.ContainerTag = htmlTag;
51+
}
4652
var result = reactComponent.RenderHtml();
4753
return new HtmlString(result);
4854
}

src/React/IReactComponent.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ public interface IReactComponent
1919
/// </summary>
2020
object Props { get; set; }
2121

22+
/// <summary>
23+
/// Gets or sets the name of the component
24+
/// </summary>
25+
string ComponentName { get; set; }
26+
27+
/// <summary>
28+
/// Gets or sets the unique ID for the container of this component
29+
/// </summary>
30+
string ContainerId { get; set; }
31+
32+
/// <summary>
33+
/// Gets or sets the HTML tag the component is wrapped in
34+
/// </summary>
35+
string ContainerTag { get; set; }
36+
2237
/// <summary>
2338
/// Renders the HTML for this component. This will execute the component server-side and
2439
/// return the rendered HTML.

src/React/ReactComponent.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,19 @@ public class ReactComponent : IReactComponent
3838
private readonly IReactSiteConfiguration _configuration;
3939

4040
/// <summary>
41-
/// Name of the component
41+
/// Gets or sets the name of the component
4242
/// </summary>
43-
private readonly string _componentName;
43+
public string ComponentName { get; set; }
4444

4545
/// <summary>
46-
/// Unique ID for the DIV container of this component
46+
/// Gets or sets the unique ID for the DIV container of this component
4747
/// </summary>
48-
private readonly string _containerId;
48+
public string ContainerId { get; set; }
49+
50+
/// <summary>
51+
/// Gets or sets the HTML tag the component is wrapped in
52+
/// </summary>
53+
public string ContainerTag { get; set; }
4954

5055
/// <summary>
5156
/// Gets or sets the props for this component
@@ -64,8 +69,9 @@ public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration con
6469
EnsureComponentNameValid(componentName);
6570
_environment = environment;
6671
_configuration = configuration;
67-
_componentName = componentName;
68-
_containerId = containerId;
72+
ComponentName = componentName;
73+
ContainerId = containerId;
74+
ContainerTag = "div";
6975
}
7076

7177
/// <summary>
@@ -81,20 +87,20 @@ public string RenderHtml()
8187
var html = _environment.Execute<string>(
8288
string.Format("React.renderToString({0})", GetComponentInitialiser())
8389
);
84-
// TODO: Allow changing of the wrapper tag element from a DIV to something else
8590
return string.Format(
86-
"<div id=\"{0}\">{1}</div>",
87-
_containerId,
88-
html
89-
);
91+
"<{2} id=\"{0}\">{1}</{2}>",
92+
ContainerId,
93+
html,
94+
ContainerTag
95+
);
9096
}
9197
catch (JsRuntimeException ex)
9298
{
9399
throw new ReactServerRenderingException(string.Format(
94100
"Error while rendering \"{0}\" to \"{2}\": {1}",
95-
_componentName,
101+
ComponentName,
96102
ex.Message,
97-
_containerId
103+
ContainerId
98104
));
99105
}
100106
}
@@ -110,7 +116,7 @@ public string RenderJavaScript()
110116
return string.Format(
111117
"React.render({0}, document.getElementById({1}))",
112118
GetComponentInitialiser(),
113-
JsonConvert.SerializeObject(_containerId, _configuration.JsonSerializerSettings) // SerializeObject accepts null settings
119+
JsonConvert.SerializeObject(ContainerId, _configuration.JsonSerializerSettings) // SerializeObject accepts null settings
114120
);
115121
}
116122

@@ -122,14 +128,14 @@ private void EnsureComponentExists()
122128
// This is safe as componentName was validated via EnsureComponentNameValid()
123129
var componentExists = _environment.Execute<bool>(string.Format(
124130
"typeof {0} !== 'undefined'",
125-
_componentName
131+
ComponentName
126132
));
127133
if (!componentExists)
128134
{
129135
throw new ReactInvalidComponentException(string.Format(
130136
"Could not find a component named '{0}'. Did you forget to add it to " +
131137
"App_Start\\ReactConfig.cs?",
132-
_componentName
138+
ComponentName
133139
));
134140
}
135141
}
@@ -143,7 +149,7 @@ private string GetComponentInitialiser()
143149
var encodedProps = JsonConvert.SerializeObject(Props, _configuration.JsonSerializerSettings); // SerializeObject accepts null settings
144150
return string.Format(
145151
"{0}({1})",
146-
_componentName,
152+
ComponentName,
147153
encodedProps
148154
);
149155
}

0 commit comments

Comments
 (0)