Html.DropDownList returns an empty string in IE, works fine in FF - html.dropdownlistfor

I have a dropdownlist that is simply a list of strings (salutations). When I submit the form, the field is an empty string no matter what value is selected.
In firefox, it works exactly as expected...but not in IE.
<tr>
<td>Salutation : </td><td><%= Html.DropDownList("Salutation", new SelectList(Salutations.SalutationList, Model.Salutation), "")%></td>
</tr>
Any help is appreciated.

Fixed by doing this instead.
<tr>
<td>Salutation : </td><td><%= Html.DropDownList("Salutation", new SelectList(Salutations.SalutationList.Select(x => new { value = x, text = x }), "value", "text", Model.Salutation), "")%></td>
</tr>

Related

How to Form Tables Correctly When HTML Template Components are Separated?

When building tables in Lit, sometimes I need to generate different parts of a table in different parts of the code. But when I put everything together, the table does not look the same as if it were declared all in one place.
See this playground for an example of the same table that's assembled two different ways. Is there any way I can make the "two halves" table look the same as the first, while still creating the elements in separate html`` blocks?
I tried creating a table in two different ways (see playground), I expected it to be the same resulting table in both instances. What actually happened is that they looked different, and I want to know why/how to correct this.
Lit does not do string concatenation and each html tag function results in a cached Template element which can be efficiently rendered. This means that each of your html tags get implicitly closed by the browser's HTML parser.
E.g.: html`<table>...` is parsed by the browser into: html`<table>...</table>`. From lit.dev documentation on "Well-formed HTML": https://lit.dev/docs/templates/expressions/#well-formed-html
Lit templates must be well-formed HTML. The templates are parsed by the browser's built-in HTML parser before any values are interpolated. Follow these rules for well-formed templates:
Templates should not contain unclosed elements—they will be closed by the HTML parser.
Therefore instead of the following structure:
// Does not work correctly - do not copy this. For demonstration purposes.
const start = html`<table>`;
const content = html`content`;
const end = html`</table>`;
const result = [start, content, end];
return html`${result}`;
// This would render as: <table></table>content<table></table>
Consider the following structure instead where each html tag function is well formed HTML:
const tableFrame = (content) => html`<table>${content}</table>`;
const content = html`content`;
// Pass the content template result into the table frame.
return tableFrame(content);
The following is your code from the playground example restructured in this way:
<script type="module">
import {LitElement, html, css} from "https://cdn.jsdelivr.net/gh/lit/dist#2/core/lit-core.min.js";
class TableExample extends LitElement {
static styles = css`table, th, td { border: 1px solid black; }`;
generateTables() {
const tables = [];
const tableRow1 = html`
<tr>
<td rowspan=2>0</td>
<td>1</td>
</tr>`;
const tableRow2 = html`
</tr>
<td>2</td>
</tr>`;
const table1 = html`
<table>
<tr>
<td rowspan=2>0</td>
<td>1</td>
</tr>
</tr>
<td>2</td>
</tr>
</table>
`;
const tableFrame = (content) => html`<table>${content}</table>`;
// Full table
tables.push(table1);
tables.push(html`<br />`);
// Use tableFrame with custom content.
tables.push(tableFrame(html`<tr><td>Custom Content</td></tr>`));
tables.push(html`<br />`);
// Use tableFrame with the two rows defined earlier.
tables.push(tableFrame([tableRow1, tableRow2]));
return tables;
}
render() {
return this.generateTables();
}
}
customElements.define('table-example', TableExample)
</script>
<table-example></table-example>
As an additional reference the documentation on Templates: https://lit.dev/docs/templates/expressions/#templates

VueJs - How to access DOM property of an element from $refs

I have an element
<tbody ref="tbody">
<tr class="row" :ref="userIndex" v-for="(userData, uid, userIndex) in users" :key="uid">
in my template. I need to access/edit the DOM property like scrollTop, verticalOffset of <tr> element. How can I achieve this?
I have tried to access using this.$refs[userIndex][0].$el but its not working. I can see all the properties in the console but I am unable to access them. However this.$refs.tbody.scrollTop works.
Below is the snap showing console.log(this.$refs)
console.log(this.$refs[userIndex])
console.log(this.$refs[userIndex][0])
As you can see when I use this.$refs[userIndex][0] I don't see the DOM properties
A $ref object will only have a $el property if it is a Vue component. If you add a ref attribute to a regular element, the $ref will a reference to that DOM Element.
Simply reference this.$refs[userIndex][0] instead of this.$refs[userIndex][0].$el.
To see the properties of that element in the console, you'll need to use console.dir instead of console.log. See this post.
But, you can access properties of the element like you would any other object. So, you could log the scrollTop, for instance, via console.log(this.$refs[userIndex][0].scrollTop).
I don't think verticalOffset exists. offsetTop does. To console log an Dom element and its property, use console.dir
Open the browser console and run this working snippet:
var app = new Vue({
el: '#app',
data: {
users: {
first: {
name: "Louise"
},
second: {
name: "Michelle"
}
}
},
mounted() {
console.dir(this.$refs[1][0])
console.log('property: ', this.$refs[1][0].offsetTop)
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<table><tbody ref="tbody">
<tr :ref="userIndex" v-for="(userData, uid, userIndex) in users" :key="uid">
<td>{{userData}}: {{userIndex}}</td>
</tr>
</tbody>
</table>
</div>

How to convert text value to number with truncating first or last character of text in protractor?

I want to get numeric value of column rate and percentage with $ and % removed from text.
I have tried replace but it is not working.
HTML code is as below:
<tbody _ngcontent_1="">
<tr class="class-1" _ngcontent_1="">
<td class="label" _ngcontent_1="">xyz</td>
<td class="rate" _ngcontent_1="">$5.00</td>
<td class="percentage" _ngcontent_1="">12.00%</td>
</tr>
Something like this i believe:
let convertToFloat = (textToConvert)=> {
let cleared = textToConvert.replace("$", "").replace("%", "");
return parseFloat(cleared)
}
let ratevalue = $('.rate').getText().then(convertToFloat)
let percentagevalue = $('.percentage').getText().then(convertToFloat)
expect(ratevalue).toEqual(5.00)
expect(percentagevalue).toEqual(12.00)
Don't forget about promises.

How to handle table data in Protractor

In Protractor, how does one handle repeated content, from say a table? For example, given the following code, that kicks out a table with 3 columns: Index, Name and Delete-Button in each row:
<table class="table table-striped">
<tr ng-repeat="row in rows | filter : search" ng-class="{'muted':isTemp($index)}">
<td>{{$index+1}}</td>
<td>{{row}}</td>
<td>
<button class="btn btn-danger btn-mini" ng-click="deleteRow(row)" ng-hide="isTemp($index)"><i class="icon-trash icon-white"></i></button>
</td>
</tr>
</table>
And in my test I need to click the delete button based on a given name. What's the best way to find this in Protractor?
I know I could grab the rows.colum({{row}}) text, get the index of that, and then click on the button[index], but I'm hoping for a more elegant solution.
For example, in Geb, you could pass a row locator to a module, that would then dice up each row with column indicators. And that solution has me eyeing Protractors map method...
You can use map or filter. The api would look like this:
var name = 'some name';
// This is like element.all(by.css(''))
return $$('.table.table-stripe tr').filter(function(row) {
// Get the second column's text.
return row.$$('td').get(2).getText().then(function(rowName) {
// Filter rows matching the name you are looking for.
return rowName === name;
});
}).then(function(rows) {
// This is an array. Find the button in the row and click on it.
rows[0].$('button').click();
});
http://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.filter
Here is how I am doing something similar in my application using Protractor against a Kendo grid:
I have a page object that has the following functions:
// Query all table rows (tr) inside the kendo grid content container
this.getGrid = function () {
return element.all(by.css('.k-grid-content tr'));
};
// Use the given rows element finder to query for the delete button within the context of the row
this.getDeleteButtonInRow = function (row) {
return row.element(by.css(".btn.delete"));
};
Then I use these functions in my test like so:
// Verify that a delete button appears in every row of the grid
var grid = pageObj.getGrid();
grid.each(function (row) {
var deleteButton = downloadsPage.getDeleteButtonInRow(row);
expect(deleteButton.isDisplayed()).toBe(true);
});
Here's my solution, based on #Andres solution, that I used in my page object:
this.deleteFriend = function(nameString) {
return this.rows.filter(function(row) {
// find the row with the name we want...
return row.$$('td').get(1).getText().then(function(name) {
return name === nameString;
});
}).then(function(filteredRows) {
filteredRows[0].$('i.icon-trash').click();
});
};

List mapping in Play2's form

I'm trying to create a form with multiple textarea, each goes with a corresponding checkbox. Basically, the application works as "If yes (the checkbox is checked), leave the textarea blank. Otherwise, fill in your explanation on why do you think it's wrong".
In models, I have
case class AnswerMapping(id: Long, status: Option[String], result: Option[String]
val form = Form[Seq[Answers](
mapping(
"details" ->
list(mapping(
"id" -> longNumber,
"status" -> optional(text),
"result" -> optional(text)
)(AnswerMapping.apply)(AnswerMapping.unapply)
))(apply)(unapply)
)
In views, I have
#helper.form(action = controllers.conflict.routes.Answer.updateAnswer(ans.id()) {
<div class="row-fluid">
<div class="span12">
#ans.details.get.zipWithIndex.map { case(detail, index) =>
#helper.textarea(
form(("details[" + index + "].result")),
'class -> "input-xlarge resizable",
'id -> ("box" + index),
'_label -> "")
}
</div>
<div class="controls">
<input value="Submit" type="submit" class="btn btn-primary">
</div>
</div>
}
The rendered HTML looks like <textarea id="box0" name="details[0].result" class="input-xlarge resizable" id="box0"></textarea>
However, when I submitted the form, I was redirected back to the same page. This is probably because I have this in my controllers, which means there's error in my form
Ans.form.bindFromRequest.fold(
formWithErrors => Ok(views.html.answer.edit(answer, formWithErrors)),
ans => { // save the answer }
My question:
Is the above, details[0].result the right syntax to access an element in a form's list
I don't quite understand why my form has errors. The two fields that needs to be filled in are marked as optional, simply because sometimes a checkbox is not checked, and sometimes the answer box is left blank. Is this perhaps because of the id field? I already set it in my apply/unapply method, so I'm not sure what I'm missing.
Thanks for all the input.
see document:Repeated values
#helper.repeat(myForm("emails"), min = 1) { emailField =>
#helper.inputText(emailField)
}