How to remove underscores using angularjs in rails? - ruby-on-rails

I am working on already developed code in AngularJS with Rails.
I am having a code which prints all the workflow states like not_found, in_process, new etc;
<td>
<div class="editable-wrapper">
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{ address.workflowState | capitalise }}</a>
</div>
</td>
Now with the above code {{ address.workflowState | capitalise }}, the page is showing as In_process, New etc;
My aim is to remove the underscores and display them as In process/ in process, Not found / not found etc. (Capitalize is not essential but have to remove underscore).

You can create a filter and use like:
HTML:
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{address.workflowState | removeUnderscores}}</a>
Filter:
filterExample.filter('removeUnderscores', function () {
return function (text) {
var str = text.replace(/_/g, ' ');
return str
};
})
DEMO FIDDLE
Here's a One Liner
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{address.workflowState.split("_").join(" ")}}</a>
DEMO FIDDLE FOR ONE LINER

You can use this filter (Disclaimer: I'm the author) that does exactly what you need.
{{ address.workflowState | capitalize:'first':'_' }}
If you want to implement it by yourself it could be something like this:
angular.module('angular-capitalize-filter',[])
.filter('capitalize', function () {
return function (input) {
if (!input) {
return input;
}
// Capitalize the first letter of a sentence
var output = input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
return output.split('_').join(' ');
}
});
And then use it as:
{{ address.workflowState | capitalize }}

You can create your own filter for replacing _ with space as bellow
angular.module('your-module-name', [])
.filter('stateformat', function() {
return function(input) {
if(input != null && input.length > 0)
return input.replace('_', ' ');
}
});
HTML
<td>
<div class="editable-wrapper">
<a e-name="states" e-ng-options="s.id as s.name for s in workflowStates" editable-select="address.workflowState" onbeforesave="updateAddress({workflowState: $data}, address)">{{ address.workflowState | capitalise | stateformat }}</a>
</div>
</td>

Related

ASP.NET MVC Filter Options in Select List (DataTable)

I created a filter section using DataTables API and it seems working fine, except for the Status column that has Select List Options.
The filter function is searching every option that contains in Select List, but I want it to search only the first option in Select List.
For example: when I input 'Manual', I need it to filter only the first row, not a second row that got options value 'Manual' in it.
Before filter:
After filter:
HTML Code (in DataTable)
#if (dealer.STATUS == "R" || dealer.STATUS == "M")
{
<td class="tdStaff" data-label="Status">
#if(#Model.SelectLists.Where(x => x.Value == dealer.STATUS).Select(x => x.Value).First() == "M")
{
<select name="statusname">
<option value="M">Manual Pay</option>
<option value="R">Reject</option>
</select>
}
else if (#Model.SelectLists.Where(x => x.Value == dealer.STATUS).Select(x => x.Value).First() == "R")
{
<select name="statusname">
<option value="R">Reject</option>
<option value="M">Manual Pay</option>
</select>
}
</td>
}
else
{
<td>#dealer.STATUS_NAME</td>
}
Filter Function
function addSearchControl(json) {
$("#myTable thead").append($("#myTable thead tr:first").clone());
$("#myTable thead tr:eq(1) th").each(function(index) {
$(this).replaceWith('<th><input type="text" placeholder="' + $(this).html() + '..." style="width:100%"></input></th>');
var searchControl = $("#myTable thead tr:eq(1) th:eq(" + index + ") input");
searchControl.on('keyup', function() {
dataTable.column(index).search(searchControl.val()).draw();
});
});
}
Expect this to filter value only the first option in Select List.
Hope you understand and any advice would be grateful, Thanks.

How to output block with handlebars dot net conditional helper?

I have the following helper for handlebars.net:
Handlebars.RegisterHelper("#is",
(writer, context, args) =>
{
string val1 = args[0].ToString();
string val2 = args[1].ToString();
if (val1 == val2)
{
//how to get block output
}
});
I am trying to test it on the following html, but I am not sure how to write out the content between {#is} and {/is} if it is true:
<div style="text-align: right;">
{{#each TeamMembers}}
{{#is this.Title 'Manager'}}
{{ this.Name }}<br />
{{ this.PersonalEmail }}<br />
{{ this.Phone }}<br />
{{/is}}
{{/each}}
</div>
Figured it out using a different signature:
Handlebars.RegisterHelper("is",
(writer,options, context, args) =>
{
string val1 = args[0].ToString();
string val2 = args[1].ToString();
if (val1 == val2)
{
options.Template(writer, (object)context);
}
});

Knockout two way Binding for Dropdrown

I am facing the issue while binding the value for dropdown from a observable array.
Model
function question(item)
{
var self = this;
self.questionId = ko.observable(item.questionId || "");
self.position = ko.observable(item.position || "");
self.position.subscribe(function (data) {
// Some Logic
}, this, 'beforeChange');
api.position.subscribe(function (data) {
// Some Logic
}
}
View Model
function viewmodel(item)
{
var self = this;
self.questionList = ko.observableArray([]);
self.questionEntity = ko.observable(new question(item));
// initially Item will be blank
self.addQuestion = function(data)
{
data.position(self.questionList().length + 1);
self.questionList.push(data);
}
}
View
<div>
question Id : <input type="text" data-bind="value: questionEntity().questionId " >
<button data-bind='click: $root.addquestion'>Add Question</button>
</div>
<table>
<tbody data-bind='foreach: questionList '>
question Id : <span data-bind='text:questionId' ></span>
position :
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position'></select>
</tbody>
</table>
Problem
I have one popup div(addQuestion) and I will add the question. and I am keep on adding that question to my observable Array(questionList)
When i add First question my value in observable array is
questionId | Position
1 | 1
When I add second record
questionId | Position
1 | 1
2 | 2
When I Add thrid record, all the previous records POSITION value(value is binded to dropdown) is being reset to 1 except last record
questionId | Position
1 | 1
2 | 1
3 | 3
fourth record
questionId | Position
1 | 1
2 | 1
3 | 1
4 | 4
after debugging I found out its problem with two way binding with Dropdown
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position'></select>
in above code if change the binding(single way) like below it works fine
<select data-bind='options: $root.positionList,optionsText: "id",optionsValue: "id" ,value: position()'></select>
But I need to subscribe an event for the dropdown.

YUI 3 html templating

Is there any way to create HTML markup in YUI like:
<div id={DivId}>
<p class={pClass}>
<span class={spanClass}> {Content} </span>
</p>
</div>
If I understand your question correctly, Y.substitute might be worth looking at.
If you haven't seen it, I'd recommend watching through the YUI 3 Sugar video at the YUI theater. Jump to 22:27 for more on Y.substitute.
I did the same thing.... Here is what I used.
var resultFormatTemplate =
'<div class="result">{first_name}, {last_name}</div>';
function resultFormat(query, results) {
return Y.Array.map(results, function (result) {
var rep = result.raw;
return Y.Lang.sub(resultFormatTemplate, {
first_name : rep['First Name'],
last_name : rep['Last Name']
});
});
};
In the Y.one tag I used resultFormatter : resultFormat to call the function.

Dynamically adding dropdowns to a form and validating them in ASP.NET MVC

I have a form with various inputs. I have a bunch of optional parameters that have some number of choices. I'd like to allow the user to select these optional parameters in the following way:
First, the user clicks the Add Component button at the bottom of the form and two new dropdowns appear above the button. The first dropdown has a list of Types that can be selected and the second one will be disabled. When the user selects a valid choice in the first dropdown, I want to populate the second dropdown with some Values that are specific to the specified Type. The user should be able to continue adding new Components (the pair of dropdowns) until all the desired optional Components are added. Ideally the form wouldn't be posted until all the fields have been filled out and the desired Components added.
My question is this: How do I design this so that when the form is submitted and there are errors, that the dynamically added fields (the Components) will remain on the page and display the correct values?
I was planning on having the Add Component button be an Ajax.ActionLink that retrieves a partialview:
<div id="divComponentHolder"></div>
<%= Ajax.ActionLink("Add a Component", "GetComponentSelector", new AjaxOptions { UpdateTargetId = "divComponentHolder", InsertionMode = InsertionMode.InsertAfter}) %>
This partial view would look something like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MVCAndWebFormsTest.Models.ComponentSelectorModel>" %>
<%= Html.Encode("Type:")%>
<%= Html.DropDownList("ComponentType", Model.ComponentTypes, "", new {onchange = "updateCompValues(this);"}) %>
<%= Html.Encode("File/Folder:")%>
<div id="selectdiv">
<% Html.RenderPartial("ComponentValueSelector", Model.ComponentValues); %>
</div>
<br/>
<script type="text/javascript" language="javascript">
function updateCompValues(obj) {
$.ajax({
url: <% Url.Action("GetCompValues") %>,
async: true,
type: 'POST',
data: { type: obj.value },
dataType: 'text',
success: function(data) { $("#selectdiv").html(data); },
error: function() {
console.log('Erreur');
}
});
}
</script>
And the ComponentValueSelector partial would be pretty simple:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MVCAndWebFormsTest.Controllers.ViewModels.ComponentValueModel>" %>
<%= Html.DropDownList("CompValue", Model.SelectList) %>
Take a look at submitting list in MVC, here are a few useful sites:
http://blogs.teamb.com/craigstuntz/2009/02/11/38013/
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
This is useful for submitting your dynamic DOM you are building up.
Another way instead of making an ajax call to render a partial view you could always directly add elements to the DOM with jquery. For example use the jquery clone ( $('element').clone(); ) method that would copy your list boxes then do some regex to change the id's of the input boxes so they have unique id/names.
As you are passing through a List of these 'choices' to your controller, you would then have to set them back in your Model and have your View iterate through them to display the correct amount of choices added.
Here is a bare bones example. This may not be the best implementation for yourself or someone else may have better ideas.
View
<% for (int i = 0; i < in Model.Results.Count; i++) { %>
//render better HTML but you should get the point!
<%= Html.Hidden("choices[" + i + "].ID", i) %>
<%= Html.DropDownList("choices[" + i + "].Choice1", ...) %>
<%= Html.DropDownList("choices[" + i + "].Choice2", ...) %>
<% } %>
- add button
jQuery
$('#addButton').click(function()
{
//say if your choice drop downs were in a table then take the last
//row and clone it
var row = $('table tr:last').clone(true);
var newId = //work out the new id from how many rows in the table
//make sure to update the id and name parameters of inputs
//of the cloned row
row.find(':input')
.attr('id', function()
{
return $(this).attr('id').replace(/\[[\d+]\]/g, '[' + newlId + ']');
//this replaces the cloned [id] with a new id
})
.attr('name', function()
{
return $(this).attr('name').replace(/\[[\d+]\]/g, '[' + newId + ']');
});
row.find(':hidden').val(newId); //update the value of the hidden input
//alert(row.html()); //debug to check your cloned html is correct!
//TODO: setup ajax call for 1st drop down list to render 2nd drop down
$('table tr:last').after(row);//add the row
return false;
});
Controller
public ActionResult YourMethod(IList<YourObject> choices, any other parameters)
{
YourViewModel model = new YourViewModel();
model.Results = choices; //where Results is IList<YourObject>
return View(model);
}
Based on advice from David Liddle, I found a different design that was a bit more elegant. It uses more jQuery and fewer partial views and Ajax requests.
Instead of adding a bunch of DropDownLists, I decided to go with a table, a pair of dropdowns and an "Add" button. When the user selects a Type option in the first dropdown, ajax is still used to retrieve the partial view for populating the second Value dropdown. Once a Value option has been selected, the user then clicks the Add button.
Using jQuery, two hidden inputs are added to the page. The naming convention in the links from David are used to name these elements (comps[0].Type and comps[0].Value). Also, a new row is added to the table with the same Type and Value for visual feedback to the user showing what has been added.
I also defined a Component class that just has Type and Value properties and added a List to the Model. In the view, I iterate over this list and add all components in the Model to the table and as hidden inputs.
IndexView
<table id="componentTable">
<tr>
<th>Type</th>
<th>Deploy From</th>
</tr>
<% foreach (Component comp in Model.comps) { %>
<tr>
<td><%= Html.Encode(comp.Type) %></td>
<td><%= Html.Encode(comp.Value) %></td>
</tr>
<% } %>
</table>
<div id="hiddenComponentFields">
<% var index = 0;%>
<% foreach (Component comp in Model.comps) { %>
<input type="hidden" name="comps[<%= Html.Encode(index) %>].Type" value="<%= Html.Encode(comp.Type) %>" />
<input type="hidden" name="comps[<%= Html.Encode(index) %>].Value" value="<%= Html.Encode(comp.value) %>" />
<% index++; %>
<% } %>
</div>
<%= Html.DropDownList("ComponentTypeDropDown", Model.ComponentTypes, "", new { onchange = "updateCompValues();"}) %>
<span id="CompValueContainer">
<% Html.RenderPartial("ComponentValueSelector", new ComponentValueModel()); %>
</span>
<span class="button" id="addComponentButton" onclick="AddComponentButtonClicked()">Add the File</span>
<span id="componentStatus"></span>
ComponentValueSelector PartialView
<%# Control Language="C#" Inherits="ViewUserControl<ComponentValueModel>" %>
<% if(Model.SelectList == null) { %>
<select id="CompValue" name="CompValue" disabled="true">
<option></option>
</select>
<% } else { %>
<%= Html.DropDownList("CompValue", Model.SelectList, "") %>
<% } %>
jQuery
function updateCompValues() {
$.ajax({
url: '<%= Url.Action("GetComponentValues") %>',
async: true,
type: 'POST',
data: { type: $("#CompValue").value },
dataType: 'text',
success: function(data) { $("#CompValueContainer").html(data); enable($("#CompValue")) },
error: function() {
console.log('Erreur');
}
});
}
function AddComponentButtonClicked() {
UpdateCompStatus("info", "Updating...");
var type = $("#ComponentTypeDropDown").val();
var value = $("#CompValue").val();
if (type == "" || value == "") { // No values selected
UpdateCompStatus("warning", "* Please select both a type and a value");
return; // Don't add the component
}
AddComponent(type, value);
}
function AddComponent(type, setting_1) {
// Add hidden fields
var newIndex = GetLastCompsIndex() + 1;
var toAdd = '<input type="hidden" name="comps[' + newIndex + '].Type" value="' + type + '" />' +
'<input type="hidden" name="comps[' + newIndex + '].Setting_1" value="' + setting_1 + '" />';
$("#hiddenComponentFields").append(toAdd);
// Add to page
// Note: there will always be one row of headers so the selector should always work.
$('#componentTable tr:last').after('<tr><td>'+type+'</td><td>'+setting_1+'</td>remove</tr>');
}
function GetLastCompsIndex() {
// TODO
alert("GetLastCompsIndex unimplemented!");
// haven't figured this out yet but something like
// $("#hiddenComponentFields input:hidden" :last).useRegExToExtractIndexFromName(); :)
}
function UpdateCompStatus(level, message) {
var statusSpan = $("#componentStatus");
// TODO Change the class to reflect level (warning, info, error?, success?)
// statusSpan.addClassName(...)
statusSpan.html(message);
}
Controller
public ActionResult Index() {
SelectList compTypes = repos.GetAllComponentTypesAsSelectList();
return View(new IndexViewModel(compTypes));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(Component[] comps, other params...) {
foreach(Component comp in comps) {
// Do something with comp.Type and comp.Value
}
return RedirectToAction(...);
}
public ActionResult GetComponentValues(string type) {
ComponentValueModel valueModel = new ComponentValueModel();
valueModel.SelectList = repos.GetAllComponentValuesForTypeAsSelectList(type);
return PartialView("ComponentValueSelector", valueModel);
}
IndexViewModel
public class IndexViewModel {
public List<Component> comps { get; set; }
public SelectList ComponentTypes { get; set; }
public IndexViewModel(SelectList types) {
comps = new List<Component>();
ComponentTypes = types;
}
}

Resources