Regex comparison in Dust - dust.js

Is there a way to use regex expression comparison using dust template.
eg:
#select key="{notes}"}
{#eq value="s+"}
sample: {notes}
{/eq}
{#default}
{notes}
{/default}
{/select}
I want any notes with 's' as the beginning, to be printed as "sample: {notes} " else it will directly print the {notes}.
Is it possible to do so with using any external helper?

You can use a helper function
Helper
dust.helpers.regexp = function(chunk, context, bodies, params) {
var regexp = new RegExp(params.pattern, params.flag);
if (regexp.test(params.term)) {
return chunk.render(bodies.block, context);
} else {
return chunk.render(bodies['else'], context);
}
}
Usage
{#regexp term=notes pattern="^[sS](\w+)" flag="g"}
sample: {notes}
{:else}
{notes}
{/regexp}
DustJS helpers

Related

changing Html.Raw into string without html markup in a razor view

Quite simple question. I have the following code
#Html.Raw(following.Description).ToString()
when this comes from database it has some markup in it (its a forum post but i want to show a snippet in the list without the markup
is there any way to remove this and replace this line or shall I just regex it from the controller?
Here is a utility class extension method that is able to strip tags from fragments without using Regex:
public static string StripTags(this string markup)
{
try
{
StringReader sr = new StringReader(markup);
XPathDocument doc;
using (XmlReader xr = XmlReader.Create(sr,
new XmlReaderSettings()
{
ConformanceLevel = ConformanceLevel.Fragment
// for multiple roots
}))
{
doc = new XPathDocument(xr);
}
return doc.CreateNavigator().Value; // .Value is similar to .InnerText of
// XmlDocument or JavaScript's innerText
}
catch
{
return string.Empty;
}
}

MVC 4 Razor - Naming javascript functions dynamically

I am trying to create the name of a function dynamically:
I set the name in razor code:
# { name="bob"; }
Then I try to create the javascript function, but the syntax is wrong.
function #name#:_onActivate() {
.....
}
How can I use #name in the name of the function?
I know im late to the party, but i had the same question and came up with this..
Use the #() Razor syntax:
function #(Model.Name)_Init()
{
.....some code...
}
Works like a charm
(http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx/)
This was found to work in writing Javascript function names dynamically
#{
#:function
#name<text>_onActivate() {
....
}
</text>
}
There is also another option:
#{
var functionStart = "function " + name + "_onActivate()";
}
#functionStart
{
...
}
This method doesn't make so much mess in Visual Studio in some cases.
This worked well for me:
#{
var someFuncName = "someFuncName";
var someFuncName2 = "someFuncName" + Model.type;
var someDynamicFunc = Model.funcName;
var someFuncNameComplete = "functionHelper()";
}
<script type="text/javascript">
function #someFuncName#{<text>()</text>}{
...
}
function #someFuncName2#{<text>(data)</text>}{
...
}
function #someDynamicFunc#{<text>()</text>}{
...
}
function #someFuncNameComplete{
...
}
</script>
If your JavaScript is in the view (rather than its own js file - though I'm not saying I think this is advisable), you can try wrapping your JS code in <text> tags, so that the parser switches back to HTML mode (vs C# mode).
Another alternative may be not naming the function dynamically but instead passing in the name as a parameter - but whether that would work may depend on your design/implementation.
First you can set the function name in a string with below structure:
#{
string name = "bob";
string funcTxt = name + "_onActivate()";
}
Then you can use this string into your function declaration:
<script>
function #funcTxt {
...
}
</script>

DustJS: Escape input from context

Doing some investigation for using dust.js, and I was wondering is there a way from preventing bad data to be rendered.
Template
Hello {name}! You have {count} new messages
Context
{
"name": "Mick",
"count": Math.PI
}
Yields, this result:
Hello Mick! You have 3.141592653589793 new messages
In this example, is there a way to escape the Math.PI, so that we can bail out and not print 3.14..
You, as the developer, have to decide what is 'bad data' and what is an acceptable alternative.
Then you must either transform it in code (eg. the node.js building the page) before it reaches dust.js, or write a helper to render whatever you want with appropriate fallback. For instance, if you want to render integers, and display some custom fallback text otherwise, you might use a helper something like this:
Create an integerOrElse function, and save it in a file, eg.
local-dust-helpers.js:
// this extends dustjs-helpers (which must therefore be in package.json)
var dust = require('dustjs-helpers');
dust.helpers.integerOrElse = function (chunk, ctx, bodies, params) {
// tap function resolves variables in params
var value = dust.helpers.tap(params.value, chunk, ctx),
fallback = dust.helpers.tap(params.fallback, chunk, ctx) || '';
// define a fallback for the fallback :) ----------------^^^^^
// for more brevity, you could do this in one line with a ternary operator
if (!isNaN(value) && parseInt(value) == value) {
return chunk.write(value);
} else {
return chunk.write(fallback);
}
}
Then require() it in your app, replacing where you would have called the vanilla dust.js:
app.js
...
var dust = require('./local-dust-helpers');
...
You can then use it just like a native dust.js directive:
template.dust
Hello {name}!
You have {#integerOrElse value='{count}' fallback='some' /} new messages

How to create a 'url_for' link helper in AngularjJS

In .NET MVC there is #Url.Action() and in RoR there is url_for()
I could not find similar url building helper in angularjs.
I'm already providing everything that is needed to build url to $routeProvider so something like: $routeProvider.urlFor("MyCtrl", {id: 5}) could be nice to have.
My main goal here is to avoid hardcoded urls in viewes and other places and to avoid repeating url/routes patterns twice.
UPDATE:
Seems like it's hard to explain what i want so here is exact example of what i want:
Instead of writing this in viewes:
<a ng-href="/product/5">foo</a>
I want to write this:
<a ng-href="urlFor("ProductCtrl", {id:5})">foo</a>
So if later i decide to change path of ProductCtrl I would not have to update url in this a element.
What would be good solution for my goals?
You could try with something like the following (just came up with it) inside your main module's run() block:
app.run(function($route, $rootScope)
{
$rootScope.path = function(controller, params)
{
// Iterate over all available routes
for(var path in $route.routes)
{
var pathController = $route.routes[path].controller;
if(pathController == controller) // Route found
{
var result = path;
// Construct the path with given parameters in it
for(var param in params)
{
result = result.replace(':' + param, params[param]);
}
return result;
}
}
// No such controller in route definitions
return undefined;
};
});
This will extend the root scope of the application with the new path() function - so it can be used anywhere in the application. It uses the $route service to get the controller names and the corresponding paths, so you won't have to repeat yourself.
Example usage:
{{ path('LibraryController', { bookId : 'x', chapterId : 'y' }) }}
Live example at: http://plnkr.co/edit/54DfhPK2ZDr9keCZFPhk?p=preview
There are numerous approaches...a custom directive or ng-click to modify $location, or using a function in ng-href to parse the url from object and have it placed as href in an <a> tag.
Example using ng-href:
HTML:
<li ng-repeat="item in items">
<a ng-href="{{url(item)}}">{{item.txt}}</a>
</li>
JS:
function Ctrl($scope){
$scope.items=[
{id:1,txt:'foo'},
{id:2,txt:'bar'}
];
$scope.url=function(item){
return '#/'+item.id
}
}
Example using ng-click and $location
HTML:
<a ng-click="newPath(item)">{{item.txt}}</a>
JS:
function Ctrl($scope){
$scope.items=[
{id:1,txt:'foo'},
{id:2,txt:'bar'}
];
$scope.newPath=function(item){
$location.path('/'+item.id)
}
}
DEMO: http://jsbin.com/ovemaq/3
In one of recent project I came up to this solution it helped me to solve my needs right in time. It will be interesting to help you to improve it to fit your usecase.
1. Move routes definition to config:
...
ROUTES: {
PAGE1: '/page1/:id',
PAGE2: '/page2/:id/:name'
},
...
2. Define routes, using values from config:
app.config(['$routeProvider', 'config', function ($routeProvider, config) {
$routeProvider.when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$routeProvider.when(config.ROUTES.PAGE1, {
templateUrl: 'partials/page1.html',
controller: 'PageOneCtrl'
});
...
$routeProvider.otherwise({
redirectTo: '/'
});
}]);
3. Set up service to provide functionality to create urls:
services.factory('routes', function (config) {
// populates `:param` placeholder in string with hash value
var parseString = function (string, parameters) {
if (!string) return '';
if (!parameters) return string;
for (var index in parameters) {
if (!parameters.hasOwnProperty(index)) continue;
string = string.replace(':' + index, parameters[index]);
}
return string;
};
return {
getPage1Link: function (urlParams) {
return '#' + parseString(config.ROUTES.PAGE1, urlParams);
}
};
});
== Drawbacks ==
With this approach I had to define getter for each route (there were less then 5, and development speed was vital)
It appears that what you want is the ui-route directive which has just been recently added to the angularui project. There is a nice set of out-of-the-box options.

MVC Razor: Helper method to render alternate content when empty

I've got some data, and sometimes that data is blank. Instead of making a bunch of crazy logic on my view I'd rather use a helper method that will render the data if it exists, and render some HTML that just says "N/A" when the string is empty/null.
Ideal syntax: #Helpers.RenderThisOrThat(Model.CustomerPhone)
If the Model.CustomerPhone (a string) is empty it will render this alternate HTML instead: <span class='muted'>N/A</span>
Here's what we have so far:
#helper RenderThisOrThat(string stringToRender, string methodToGetAlternateText = null)
{
#RenderThisOrThat(MvcHtmlString.Create(stringToRender), methodToGetAlternateText)
}
#helper RenderThisOrThat(MvcHtmlString stringToRender, string methodToGetAlternateText = null)
{
if (string.IsNullOrWhiteSpace(stringToRender.ToHtmlString()))
{
if (!string.IsNullOrWhiteSpace(methodToGetAlternateText)) {
#methodToGetAlternateText
}
<span class='muted'>N/A</span>
}
#stringToRender
}
This works just fine until we want to pass something other than a string into either parameter. For example when we have an email address we want it to be a link to that email and not just the string of the email.
#Helpers.RenderThisOrThat(##Html.DisplayFor(m => m.CustomerEmail))
It gives us the error: "Cannot convert lambda expression to type 'string' because it is not a delegate type"
We are at a loss for how to make this work... any help here?
You're looking for a helpers that will take a string and:
If the string is not empty, render that string.
If the string is not empty, render a given template.
If the string is empty, render "N/A" html.
If the string is empty, render a given template.
When passing a razor block to a function as a parameter, razor packages the block as Func. Change the parameters in the helper functions to take that type of delegate and don't forget to call those delegates (I chose to pass null).
These helpers should handle those scenarios.
Solution
#helper RenderThisOrThat(string stringToRender, Func<object, IHtmlString> leftTemplate = null, Func<object, IHtmlString> rightTemplate = null)
{
var shouldRenderLeft = !string.IsNullOrWhiteSpace(stringToRender);
leftTemplate = leftTemplate ?? (o => MvcHtmlString.Create(stringToRender));
#RenderThisOrThat(shouldRenderLeft, leftTemplate, rightTemplate)
}
#helper RenderThisOrThat(bool shouldRenderLeft, Func<object, IHtmlString> leftTemplate, Func<object, IHtmlString> rightTemplate = null)
{
var shouldRenderRight = !shouldRenderLeft;
if (shouldRenderRight)
{
if (rightTemplate != null)
{
#rightTemplate(null)
}
else
{
<span class='muted'>N/A</span>
}
}
else
{
#leftTemplate(null)
}
}
Examples
1. #Helpers.RenderThisOrThat(Model.StringWithBob)
2. #Helpers.RenderThisOrThat(Model.StringWithNull)
3. #Helpers.RenderThisOrThat(Model.StringWithBob, #<span>I'm #Model.StringWithBob</span>)
4. #Helpers.RenderThisOrThat(Model.StringWithNull, #<span>I'm #Model.StringWithBob</span>)
5. #Helpers.RenderThisOrThat(Model.StringWithBob, #<span>I'm #Model.StringWithBob</span>, #<span>What about Bob?</span>)
6. #Helpers.RenderThisOrThat(Model.StringWithNull, #<span>I'm #Model.StringWithBob</span>, #<span>What about Bob?</span>)
Will output:
Bob
<span class='muted'>N/A</span>
<span>I'm Bob</span>
<span class='muted'>N/A</span>
<span>I'm Bob</span>
<span>What about Bob?</span>
This is an awfully complex solution to a simple problem. You don't need to create complex views, in fact, you should be using an Editor/DisplayTemplate, then you put your logic in the template and it's done once, without all the need for extra inclusion of helper functions, or anything else.
You can also go a step further here, because in this case you're rendering an email address. You apply a DataType attribute to your model and then specify an Phone Number rendering type.
public class MyModel {
[DataType(DataType.PhoneNumber)]
public string PhoneNumber {get;set;}
}
Then you create a folder in ~/Views/Shared called DisplayTemplates and in that folder create a file called PhoneNumber.cshtml, in it you do this:
#model string
#if (string.IsEmptyOrWhiteSpace(Model)) {
#:<span class='muted'>N/A</span>
} else {
#: <span>#Model</span>
}
Then, in your view:
#Html.DisplayFor(x => x.PhoneNumber)
That's it, no complex logic in your view, no convluted helper functions everywhere. This is simple, easy, and maintainable. You can do the same for Email address as there is an EmailAddress datatype as well.
MVC has a lot of very good functionality built-in that most people simply do not use, because they haven't spent any real time learning it.

Resources