Sitefinity Feather Designer Tip: Updating Fields Programatically

I recently needed to create a custom designer for a Sitefinity MVC Widget that would allow a property to be filled in programatically (such as clicking an option in a list). Populating the field was simple enough using jQuery, and here is a very simple example demonstrating the desired behavior:

<fieldset>
<div class="form-group">
<label for="message">Message:</label>
<input name="message" id="message" ng-model="properties.MyProperty.PropertyValue" />
</div>
</fieldset>

<hr />
<p>Preload a message by clicking the button below.</p>
<button id="loadButton">Load</button>

<script type="text/javascript">
$(function () {
$("#loadButton").on("click", function () {
var messageInput = $("#message");
messageInput.val("preloaded message");
});
})
</script>

Clicking the button does indeed did populate the message property:

sitefinity-feather-designer-preload-message

However, when I saved the changes, the output of the widget message property was still blank:

sitefinity-feather-designer-preloaded-message-empty

It turns out that this makes sense, because the widget designer is using Angular JS to bind its properties back to the widget, and updating the input field via jQuery isn’t actually triggering the binding.

Fortunately this was easy enough to fix by adding a manual trigger to the change event in the click handler:

$("#loadButton").on("click", function () {
var messageInput = $("#message");
messageInput.val("preloaded message");
messageInput.trigger("change");
});

This saves the field changes back to the model, and displays the saved message properly in the widget output:

sitefinity-feather-designer-preloaded-message

Now, out of sheer curiosity i wondered if there was a way to do this in straight JavaScript and Angular, instead of mixing and matching with jQuery. After searching the web a bit I found just the solution I was seeking on StackOverflow: http://stackoverflow.com/a/22942828

I followed the example and handled the click event of the button, manually binding to the same scope properties, and sure enough, it works!

Here is the updated code for the designer:

<fieldset>
<div class="form-group">
<label for="message">Message:</label>
<input name="message" id="message" ng-model="properties.MyProperty.PropertyValue" />
</div>
</fieldset>

<hr />
<p>Preload a message by clicking the button below.</p>

<button id="loadButton" onclick="loadMessage()">Load</button>

<script type="text/javascript">
function loadMessage() {
var message = document.getElementById("message");
var scope = angular.element(message).scope();
scope.properties.MyProperty.PropertyValue = "preloaded message";
scope.$digest();
}
</script>

The jQuery solution works well enough, but it’s interesting to discover this alternative method, and thought it might be worth sharing. I’m interested to see if accessing the scope this way might allow some other helpful designer tricks. I plan to do some experimenting, and if it yields anything interesting, I’ll be sure to followup with another post.

In the meantime, as always I hope this was helpful, and thanks for reading!


Originally published at Falafel Software Blog.