I have this HTML structure:
<tr id="post-7053" class="iedit author-other level-0 post-7053 type-poi status-publish hentry webmapp_category-corbezzolo" data-id="7053">
<th scope="row" class="check-column">
<label class="screen-reader-text" for="cb-select-7053">
Seleziona 594 </label>
<input id="cb-select-7053" type="checkbox" name="post[]" value="7053">
<div class="locked-indicator">
<span class="locked-indicator-icon" aria-hidden="true"></span>
<span class="screen-reader-text">
“594” è bloccato </span>
</div>
</th>
<td class="5da0bb937bd9f column-5da0bb937bd9f has-row-actions column-primary column-postid" data-colname="ID">7053
I have to take the value of an ID and compare it on another site:
i have to get the first table id i managed to get it with this cypress command:
id = cy.get('tbody#the-list td').first().invoke('val')
only that when I go to compare the value of the variable id. it never enters the if branch. While if I put a value like 7156 or other it enters the if branch and makes the comparison.
below the test code:
describe('Registration', () => {
const email = 'nedo#go.br'
const password = 'pedhu'
var id
it('create new Nedo', () => {
cy.visit('https://test.nedo/wp-admin')
cy.get('input[name=log]').type(email)
cy.get('input[name=pwd]').type(password)
cy.get('input#wp-submit').click()
cy.visit('https://test.nedo/edit.php?post_type=nedo')
id = cy.get('tbody#the-list td').first().invoke('val')
})
it('id', () => {
cy.visit('https://nedostaging.z.hu/login')
cy.get('input[name=email]').type('team#nedo.hi')
cy.get('input[name=password]').type('nedo')
cy.get('button').contains('Login').click()
cy.get('#hometable > tbody > tr > td:nth-child(4)').each(($e, index, $list) => {
const text = $e.text()
cy.log(id)
if (text.includes(id)) {//if I put a number instead of id it works
assert.strictEqual(text, '{"id":'+id+'}', 'id nedo ok')
}
})
})
cy.log(id):
For handling same-origin policies, you can write "chromeWebSecurity": false in your cypress.json file. But this will only work with the chrome browser.
describe('Registration', () => {
const email = 'nedo#go.br'
const password = 'pedhu'
before(() => {
cy.visit('https://test.nedo/wp-admin')
cy.get('input[name=log]').type(email)
cy.get('input[name=pwd]').type(password)
cy.get('input#wp-submit').click()
cy.visit('https://test.nedo/edit.php?post_type=nedo')
cy.get('tbody#the-list td').first().invoke('val').as('id')
})
it('id', () => {
cy.visit('https://nedostaging.z.hu/login')
cy.get('input[name=email]').type('team#nedo.hi')
cy.get('input[name=password]').type('nedo')
cy.get('button').contains('Login').click()
cy.get('#id').then((id) => {
cy.get('#hometable > tbody > tr > td:nth-child(4)').each(($e, index, $list) => {
const text = $e.text()
cy.log(id)
if (text.includes(id)) { //if I put a number instead of id it works
assert.strictEqual(text, '{"id":' + id + '}', 'id nedo ok')
}
})
})
})
})
Related
Q: If the value in one dropdown changed, how to reload the values for the second dropdown?
When user change the category dropdown, then I want to show the subcategory in the dropdown
Frontend: VueJs (v3)
Server Side Rendering: IneratiaJs
Backend: Laravel (v9)
VueComponent
const props = defineProps({
errors: Object,
categories: Object,
subcategories: Object,
})
const form = useForm({
category_id: '',
subcategory_id: '',
name: '',
price: '',
discount: '',
image: 'sample',
description: ''
});
let getSubcategory = (event) => {
if(event.target.value !== "") {
Inertia.reload({
'category_id': event.target.value
},
{ only: ['subcategories'],
onSuccess: page => {
alert();
console.log('onSuccess');
console.log(props.categories);
console.log(props.subcategories);
console.log(page);
}
}
);
}
}
const submit = () => {
form.post(route('store.subcategory'), {
onFinish: () => form.reset(),
});
};
Vue Template
<template>
<Head title="Add Product" />
<BreezeAuthenticatedLayout>
<template #header>
<form #submit.prevent="submit">
<div class="mt-4">
<BreezeLabel for="category_id" value="Category Name" />
<select #change="getSubcategory" v-model="form.category_id" id="category_id" class="block mt-1 w-full">
<option value="">Select Category</option>
<option v-for="category in categories" :value="category.id">{{ category.name }}</option>
</select>
<div v-if="errors.category_id" class="text-red-400">
{{ errors.category_id }}
</div>
</div>
<div class="mt-4">
<BreezeLabel for="subcategory_id" value="Subcategory Name" />
<select v-model="form.subcategory_id" id="subcategory_id" class="block mt-1 w-full">
<option value="">Select Sategory</option>
<option v-for="subcategory in subcategories" :value="subcategory.id">{{ subcategory.name }}</option>
</select>
<div v-if="errors.subcategory_id" class="text-red-400">
{{ errors.subcategory_id }}
</div>
</div>
</form>
</BreezeAuthenticatedLayout>
</template>
Laravel Route: routes/web.php
Route::get('/create/product/{category_id?}', [ProductController::class, 'create'])->name('create.product'); //Form: Create Product
Product Controller: ProductController.php
public function create($category_id = null)
{
return Inertia::render('Product/Create', [
//I want Evaluated immediately on Page Load.
'categories' => $categories = Category::all(),
//Want Lazy load here.
'subcategories' => function(){
if(!empty($category_id)){
$category = Category::find($category_id);
$subcategories = $category->subcategories()->get();
}
},
]);
}
After fixing Create method in Product Controller and script setup it's working
public function create($category_id = null)
{
return Inertia::render('Product/Create', [
// ALWAYS included on first visit - OPTIONALLY included on partial reloads - ALWAYS evaluated
'categories' => Category::has('subcategories')->get(),
// NEVER included on first visit - OPTIONALLY included on partial reloads - ONLY evaluated when needed
'subcategories' => Inertia::lazy(fn () =>
Subcategory::with('category')->where('category_id', '=', $category_id)->get()
),
]);
}
Vue SCRIPT: I was sending wrong parameters. Then I saw correct way of partial relaod on official site
let getSubcategory = (event) => {
if(event.target.value !== "") {
Inertia.visit(
route('create.product', {
category_id: event.target.value
}),{
only: ['subcategories'],
preserveState: true,
preserveScroll: true,
}
);
}
}
I have a profile page that displays the user info. The page shows the user name / email and a button to create a list.
I can also edit the name and email correctly, and it reflects in the firebase instantaneously. Ok. I get the user data and I can edit it.
What I'm trying to do now is to show the lists that the user has created.
Look, this user has created one list, and what is returned to me is that he doesn't have lists.
I'll try to shorten the code as much as possible:
<script>
imports.....
import { db } from '../../firebase.config.js'
let listings = []
let auth = getAuth()
// fetch the user's listings
const fetchUserListings = async () => {
const listingsRef = collection(db, 'listings')
const q = query(
listingsRef,
where('userRef', '==', auth.currentUser.uid),
orderBy('timestamp', 'desc')
)
const querySnap = await getDocs(q)
querySnap.forEach((doc) => {
return listings.push({
id: doc.id,
data: doc.data()
})
})
}
fetchUserListings()
</script>
<!-- display the user's listings -->
<div>
{#if listings.length > 0}
<p class="listingText">My lists</p>
{#each listings as listing}
<ListingItem listing={listing.data} id={listing.id} />
{/each}
{:else}
<p class="noListings">You have no lists</p>
{/if}
</div>
My ListItem component:
<script>
export let listing
export let id
export let handleDelete
import DeleteIcon from '../../static/assets/svg/deleteIcon.svg'
</script>
<li class="categoryListing">
<a href={`/category/${listing.type}/${id}`} class="categoryListingLink">
<img src={listing.imgUrls[0]} alt={listing.name} class="categoryListingImg" />
<div class="categoryListingDetails">
<p class="categoryListingLocation">
{listing.location}
</p>
<p class="CategoryListingName">
{listing.name}
</p>
<p class="categoryListingPrice">
${listing.offer ? listing.discountedPrice : listing.regularPrice}
{listing.type === 'rent' ? '/ por mês' : ''}
</p>
<div class="categoryListingInfoDiv">
<img src="/assets/svg/bedIcon.svg" alt="cama" />
<p class="categoryListingInfoText">
{listing.bedrooms > 1 ? `${listing.bedrooms} camas` : `${listing.bedrooms} cama`}
</p>
<img src="/assets/svg/bathtubIcon.svg" alt="banheiro" />
<p class="categoryListingInfoText">
{listing.bathrooms > 1
? `${listing.bathrooms} banheiros`
: `${listing.bathrooms} banheiro`}
</p>
</div>
</div>
</a>
{#if handleDelete}
<DeleteIcon
class="removeIcon"
fill="rgb(231, 76, 60)"
onClick={() => {
handleDelete(listing.id, listing.name)
}}
/>
{/if}
</li>
Just when you think you've reached the simplest part, it's still tough.
Update:
I think that the problem is in firebase. The "docs" are empty:
Now I am in serious trouble!
querySnap.forEach((doc) => {
return listings.push({
id: doc.id,
data: doc.data()
})
})
I see two things here. The less important: The .forEach() method returns undefined, so the return is redundant. The more important: the .push() alone won't automatically trigger updates. Have a look at this section in the Docs
Did you try logging listings? I assume the data is there, it's just not displayed, so I propose to change this part to
querySnap.forEach((doc) => {
listings = [...listings, {
id: doc.id,
data: doc.data()
}]
})
or
querySnap.forEach((doc) => {
listings.push({
id: doc.id,
data: doc.data()
})
listings = listings
})
I am using buefy autocomplete input fields in my nuxtjs project, this is location search box, what i want is just for mobile device, when i click the input field, it should overlay on full screen with suggestion like i attached screenshot below and after select suggestion, it should close and return to normal.
here is my simple auto complete input field code.
<template>
<b-autocomplete
v-model="pickupairport"
:data="airports"
name="pickupairport"
class="ttc-search-input"
icon="map-marker-outline"
placeholder="Pickup Airport"
field="name"
:loading="isFetching"
#typing="getairports"
#select="(option) => (aptselected = option)"
>
<template slot-scope="props">
<div class="media">
<div class="media-content">
{{ props.option.name }}
<br />
<small> {{ props.option.cityName }}, {{ props.option.countryName }} </small>
</div>
</div>
</template>
</b-autocomplete>
</template>
<script>
import { debounce } from 'lodash'
export default {
data() {
return {
pickupairport: '',
airports: [],
aptselected: null,
isaptFetching: false,
}
},
methods: {
getairports: debounce(function (pickupairport) {
const aptsearchq = this.pickupairport
if (!pickupairport.length) {
this.airports = []
return
}
this.isaptFetching = true
fetch(`https://api.myurl.com/api/transfers/aplist?querystring=${aptsearchq}`)
.then((response) => {
return response.json()
})
.then((data) => {
this.airports = []
data.response.forEach((item) => this.airports.push(item))
})
.catch((error) => {
this.airports = []
throw error
})
.finally(() => {
this.isaptFetching = false
})
}, 500),
},
}
</script>
What I want to achieve is like this GIF - https://i.imgur.com/zOYPwBI.gif
What I have now is like this GIF - https://imgur.com/9ZBZzxa
i tried to find something related, but couldn't find, if any suggestion on how to achieve that, it would be helpful for me.
if(data[keyvar]==false)
{
jQuery('#BtnsaveAjax').prop("disabled", false).removeClass("k-state-disabled");
}
After I execute this statement the function which is present on the save button is not getting called. Do I need to add or remove any more classes to get that function back?
I want to try to answer your question but first what i grasp from your question is
i have a grid.. and to edit it i have a popup window.. on which there
are two buttons.. edit and save.. i have two view modes.. edit and
view.. in edit mode the save button is disabled and in view mode save
button is disabled..
so now when i click "the button" here i think refers to edit button then i want my save button to enable. So far this is what i've got,
first when you click view details you will see save button disabled
while edit button enabled,
then when you click edit button the save button will be enabled
DEMO
This is what my popup looks like.. so now when i click my edit button i want the save button to get enabled.. so buy adding that k-State-disabled i could manage that.. but now when i click my save button.. the click function i have added on save is not firing..
this is my code for that popup page .. and the Editable is a dictionary which contains the disabled value for ta particular kendo widget.
#using Kendo.Mvc.UI;
#using Newtonsoft.Json;
#using SampleUIApp.Areas.AreaOne.Models;
#using SampleUIApp.Common;
#model SampleUIApp.Areas.AreaOne.Models.MemberModel
<script type="text/javascript">
$(document).ready(function ()
{
// For setting control mode
// It is observed that Kendo Multiselect does not accept value through below code
// change mode of multiselect like done below in the same view
var Edit = #(Html.Raw(JsonConvert.SerializeObject((Dictionary<string, bool>)ViewBag.Editable)));
for ( keyVar in Edit )
{
if (keyVar.search("Btn") != -1) {
jQuery('#' + keyVar).attr("disabled", Edit[keyVar]);
} else {
jQuery('#' + keyVar).prop("readonly", Edit[keyVar]);
}
}
var viewMode = #Html.Raw(Json.Encode(ViewBag.ViewMode));
if(viewMode == 'ADD')
{
$("#LoanGrid1").remove();
}
var title = viewMode + ' MEMBER';
setTitle(title);
});
function setViewMode(data) {
//for ( keyVar in data ) {
// if (keyVar.search("Btn") != -1) {
// jQuery('#' + keyVar).attr("disabled", data[keyVar]);
// }
// else {
// jQuery('#' + keyVar).prop("readonly", data[keyVar]);
// }
for ( keyVar in data ) {
if (keyVar.search("Btn") != -1) {
if(data[keyVar]==true){
jQuery('#' + keyVar).prop("disabled", true).addClass("k-state-disabled");
}
else{
jQuery('#' + keyVar).prop("disabled", false).removeClass("k-state-disabled");
}
}
else {
jQuery('#' + keyVar).prop("readonly", data[keyVar]);
}
}
}
function onAdditionalData() {
return {
text: $("#CityName").val()
};
}
function AccessModelDetails() {
var data = #Html.Raw(Json.Encode(this.Model));
alert(data.Remark);
}
function UpdateModelDetails() {
// var model = $('form').serialize();
// var data = Sys.Serialization.JavaScriptSerializer.deserialize(model);
// alert('model: ' + data.Remark);
$("#Remark").val("Remark Updated");
}
function saveDetails() {
alert('Calling : saveDetails');
var model = $("form").serialize();
Save(model); // Save Function is Written On Parent View
}
function Edit() {
var mode = 2; // 2 For Edit
var Fid = 0;
var viewName = 'MemberEditor';
var actionURL = '#Url.Action("setViewMode", "Member")';
$.ajax({
type: "POST",
data: {
Mode: mode,
lFeatureId: Fid,
ViewName: viewName
},
url: actionURL,
success: function (result) {
setViewMode(result);
}
});
}
// This Function will be called when an item is got selected from Multiselect Control
// Used for Member role
// here is a sample methos to get the selected item.
function OnSelectMemberRole(e) {
var dataItem = this.dataSource.view()[e.item.index()];
alert("event :: select (" + dataItem.MemberRoleName + " : " + dataItem.MemberRoleId + ")");
}
</script>
#using (Html.BeginForm())
{
<div class="editor">
<div id="DIV_Line07" class="line">
<div id="DIV_Buttons" class="col100" style="float: right">
#*
1.Below is the kendo button to call server side controller action by using MultiButton Attribute
2. Have to Set HtmlAttributes as follows
* name = Given Name With MutiButton Attribute
* type = "submit",
* value = Given Name With MutiButton Attribute
3. .Name(Given Name With MutiButton Attribute)
4. .Content("Caption Of Button")
*#
#(Html.Kendo().Button()
.Name("BtnEditAjax")
.Content("Edit - AJAX")
.HtmlAttributes(new { style = "float:right", type = "button" })
.Events(ev => ev.Click("Edit"))
)
#* #(Html.Kendo().Button()
.Name("Btnsave")
.HtmlAttributes(new { style = "float:right", name = "Btnsave", type = "submit", value = "save" })
.Content("Save - Server")
)*#
#*
1.Below is the kendo button to call server side controller action by using Javascript Function With Ajax
2. Have to Set HtmlAttributes as follows
* type = "button",
3. .Name(Name Of The Button)
4. .Content("Caption Of Button")
5. Events(ev => ev.Click("Javascript Function Name"))
*#
#(Html.Kendo().Button()
.Name("BtnsaveAjax")
.Content("Save - AJAX")
.HtmlAttributes(new { style = "float:right", type = "button" })
)
#(Html.Kendo().Button()
.Name("AccessModelinJS")
.Content("Access Model In JS")
.HtmlAttributes(new { style = "float:right", type = "button" })
.Events(ev => ev.Click("AccessModelDetails"))
)
#(Html.Kendo().Button()
.Name("UpdateModelinJS")
.Content("Update Model In JS")
.HtmlAttributes(new { style = "float:right", type = "button" })
.Events(ev => ev.Click("UpdateModelDetails"))
)
</div>
</div>
<div id="DIV_Line00" class="line">
<div id="DIV_Fname" class="col33">
#Html.HiddenFor(model => model.MemberId)
<label>
First Name - Upper Case
</label>
#*To make textbox uppercase set style's "text-transform" Attribute's value as "uppercase" in html HtmlAttributes*#
#(Html.Kendo().TextBoxFor(m => m.FirstName)
.Name("FirstName")
.HtmlAttributes(new { #class = "width100", style = " text-transform: uppercase" })
)
</div>
<div id="DIV_MName" class="col33">
<label>
Middle Name - Lower Case
</label>
#*To make textbox lowercase set style's "text-transform" Attribute's value as "lowercase" in html HtmlAttributes*#
#Html.Kendo().TextBoxFor(m => m.MiddleName).Name("MiddleName").HtmlAttributes(new { #class = "width100", style = " text-transform: lowercase" })
</div>
<div id="DIV_LName" class="col33">
<label>
Last Name - Alphabets Only
</label>
#*To make textbox AlphaOnly set pattern Attribute's value as "[A-Za-z\\s]*" in html HtmlAttributes*#
#Html.TextBoxFor(m => m.LastName, new { id = "LastName", #class = "width100 k-textbox", type = "text", pattern = "[A-Za-z\\s]*" })
</div>
</div>
<div id="DIV_Line01" class="line">
<div id="DIV_Height" class="col15">
<label>
DOB - Min & Max
</label>
#Html.ValidationMessageFor(model => model.DateOfBirth)
#(Html.Kendo().DatePickerFor(m => m.DateOfBirth)
.Min(new DateTime(1970, 01, 01))
.Max(new DateTime(2014, 11, 30))
.HtmlAttributes(new { #class = "width100" })
.Format("dd/MM/yyyy")
)
</div>
<div id="DIV_Membe rName" class="col18">
<label>
Age - Integer
</label>
#Html.ValidationMessageFor(model => model.Age)
#Html.Kendo().IntegerTextBoxFor(m => m.Age).HtmlAttributes(new { #class = "width100" })
</div>
<div id="DIV_Age" class="col15">
<label>
Height-Decimal 3
</label>
#*Format as "#.000" specifies that 3 decimals will be displayed, Number of 0s in the format Specifies number of decimals*#
#Html.ValidationMessageFor(model => model.Height)
#Html.Kendo().NumericTextBoxFor(m => m.Height).HtmlAttributes(new { #class = "width100" }).Format("#.000")
</div>
<div id="DIV_Country" class="col18">
<label>
StateAutoComplete
</label>
#* 1.Name Of the autocomplete must be ur property name of the model so that it could bind selected value to model .
2.List for autocomplete will only contains value and does not support Id Value pair pattern(In Used Version of kendo).
*#
#(Html.Kendo().AutoCompleteFor(m => m.StateName)
.Name("StateName")
.DataTextField("StateName")
.BindTo((System.Collections.IEnumerable)ViewData["states"]).HtmlAttributes(new { #class = "width100" })
)
</div>
<div id="DIV_CityServer" class="col33">
<label>
City-AutoComplete Server Filtering
</label>
#* 1.Name Of the autocomplete must be ur property name of the model so that it could bind selected value to model .
2.List for autocomplete will only contains value and does not support Id Value pair pattern(In Used Version of kendo).
*#
#(Html.Kendo().AutoCompleteFor(m => m.CityName)
.Name("CityName")
.DataTextField("CityName")
.MinLength(3)
//.BindTo((System.Collections.IEnumerable)ViewData["cities"]).HtmlAttributes(new { #class = "width100" })
.DataSource(
source =>
{
source.Read(read => { read.Action("GetCities", "Member").Data("onAdditionalData"); });
source.ServerFiltering(true);
})
.HtmlAttributes(new { #class = "width100" })
)
</div>
</div>
<div id="DIV_Line02" class="line">
<div id="DIV_DateOfBirth" class="col33">
<label>
Member Type - DropDownList
</label>
#*
0.List can be bind to DropDownListFor using "BindTo" or using "DataSource".
1.Name Of the DropDownListFor must be ur property name of the model so that it could bind selected value to model .
2.List for DropDownListFor will contains Id Value pair .
3.Selected Value will be Value of DataValueField - ".DataValueField("MemberTypeId")"
4.Selected Value will bind to model property given as name to DropDownListFor
*#
#(Html.Kendo().DropDownListFor(m => m.MemberType)
.Name("MemberType")
.DataTextField("MemberTypeName")
.DataValueField("MemberTypeId")
.HtmlAttributes(new { #class = "width100" })
.Filter("contains")
.BindTo((System.Collections.IEnumerable)ViewData["memberTypes"])
//.DataSource(
// source =>
// {
// source.Read(read => { read.Action("GetMemberTypes", "Member"); });
// })
)
</div>
<div id="DIV_MemberRole" class="col33">
<label>
Member Role - MultiSelect
</label>
#*
0.List can be bind to MultiSelectFor using "BindTo" or using "DataSource".
2.List for MultiSelectFor will contains Id Value pair .
1.Name Of the MultiSelectFor must be ur property name of the model so that it could bind selected values to model.
2.Type of property Specified in Name of MultiSelectFor has to be a collection type for example List<long> or List<string>.
3.Selected Values will be Values of DataValueField - ".DataValueField("MemberRoleId")"
4.Selected Values will bind to model property given as name to MultiSelectFor
*#
#(Html.Kendo().MultiSelectFor(m => m)
.Name("MemberRoleList")
.DataTextField("MemberRoleName")
.DataValueField("MemberRoleId")
.BindTo((System.Collections.IEnumerable)ViewData["memberRoles"])
.Events(e => e.Select("OnSelectMemberRole"))
//.DataSource(
// source =>
// {
// source.Read(read => { read.Action("GetMemberRoles", "Member"); });
// })
)
</div>
<div id="DIV_Mobile" class="col33">
<label>
Mobile - Mobile Mask
</label>
#*
1. Specifying Mask As "0000000000" allows to enter only 10 Digits.
*#
#Html.ValidationMessageFor(model => model.Mobile)
#(Html.Kendo().MaskedTextBoxFor(m => m.Mobile)
.Mask("0000000000")
.HtmlAttributes(new { #class = "width100" })
)
</div>
</div>
<div id="DIV_Line03" class="line">
<div id="DIV_Email" class="col33">
<label>
Email - With Validation
</label>
#*
1. For Email Validation On UI, Use Html.TextBoxFor
2. Set Attributes as follows
* type = "email"
* #class = "k-textbox"
* style = " text-transform: lowercase"
*#
#Html.TextBoxFor(model => model.Email, new { #class = "k-textbox width100", type = "email", style = " text-transform: lowercase" })
</div>
<div id="DIV_PIN" class="col33">
<label>
PIN - Mask
</label>
#*
1. Specifying Mask As "000000" allows to enter only 6 Digits.
*#
#(Html.Kendo().MaskedTextBoxFor(m => m.PIN)
.Mask("000000")
.HtmlAttributes(new { #class = "width100" })
)
</div>
<div id="DIV_Phone" class="col33">
<label>
Phone - Mask
</label>
#*
1. Specifying Mask As "(999) 000-0000" allows to enter Digits within specified mask.
*#
#(Html.Kendo().MaskedTextBoxFor(m => m.Phone)
.Mask("(999) 000-0000")
.HtmlAttributes(new { #class = "width100" })
)
</div>
<div id="DIV_Line05" class="line">
</div>
<div id="DIV_Line06" class="line">
<div id="DIV_Remark" class="col100">
<label>
Remark - Text Area
</label>
#*
To Use Text Area us helper Html.TextAreaFor
2. Set Attributes as follows
* #class = "k-textbox"
* style = " text-transform: lowercase"
* rows = as much U Want
* cols = as much U Want
*#
#Html.TextAreaFor(m => m.Remark, new { #class = "k-textbox width100", rows = "2", cols = "50" })
#Html.HiddenFor(m => m.Remark, new { id = "Remark" })
#* <textarea class="k-textbox" rows="2" cols="50" >
</textarea>*#
</div>
</div>
<div id="DIV_Phone" class="col100">
<label>
Loan Details
</label>
#(Html.Kendo().Grid<LoanModel>()
.Name("LoanGrid1")
.Columns(columns =>
{
columns.Bound(m => m.LoanNumber).Filterable(false).Title("Loan Number").Width("20%").HtmlAttributes(new { #style = "font-size:x-small" });
columns.Bound(m => m.ROI).Filterable(false).Title("ROI").Width("10%").Format("{0:N2}").HtmlAttributes(new { #style = "font-size:x-small" });
columns.Bound(m => m.Period).Filterable(false).Title("Period").Width("10%").Format("{0:N2}").HtmlAttributes(new { #style = "font-size:x-small" });
columns.Bound(m => m.LoanAmount).Filterable(false).Title("Loan Amount").Width("10%").Format("{0:N2}").HtmlAttributes(new { #style = "font-size:x-small" });
columns.Bound(m => m.OtstngAmount).Filterable(false).Title("Outstanding amount").Width("10%").Format("{0:N2}").HtmlAttributes(new { #style = "font-size:x-small" });
columns.Command(cmd => cmd.Destroy());
})
.Pageable()
.Scrollable(config => config.Enabled(false))
.Filterable(config => config.Mode(GridFilterMode.Menu))
.Sortable()
.Resizable(config => { config.Columns(true); })
.Reorderable(config => { config.Columns(true); })
.DataSource(source => source
.Ajax()
.PageSize(5)
.Model(model =>
{
model.Id(m => m.MemberId);
})
.Read(read => read.Action("FetchMemberLoanList", "Member", new { area = "AreaOne" }))
.Destroy(del => del.Action("Destroy", "Member", new { area = "AreaOne" }))
)
)
</div>
</div>
</div>
}
Working on learning bootstrap and knockout.js. This is more of a knockout question.
I would like to populate a new row of a table (using addSeat function), and if the name field on that new row is empty, add the bootstrap 'error' class to the row. It is empty by default. Once the name field is entered, the style should change to 'success'.
The basic code is taken from the Seat Reservation samples. Here is the markup:
<div id="food" class="span10">
<h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2>
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
</tr></thead>
<tbody data-bind="foreach: seats">
<tr data-bind="css: isnameBlank">
<td><input data-bind="value: name" /></td>
<td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
<td data-bind="text: formattedPrice"></td>
<td><i class="icon-remove"></i>Remove</td>
</tr>
</tbody>
</table>
<button data-bind="click: addSeat, enable: seats().length < 8">Reserve another seat</button>
<h3 data-bind="visible: totalSurcharge() > 0">
Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>
</div>
Here is the js file:
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = ko.observable(name);
self.meal = ko.observable(initialMeal);
self.formattedPrice = ko.computed(function () {
var price = self.meal().price;
return price ? "$" + price.toFixed(2) : "None";
});
self.isnameBlank = ko.computed(function () {
var ib = self.name().length;
console.log(ib);
return ib == 0 ? "warning" : "success";
}, self);
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableMeals = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
];
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[0])
]);
// Computed data
self.totalSurcharge = ko.computed(function () {
var total = 0;
for (var i = 0; i < self.seats().length; i++)
total += self.seats()[i].meal().price;
return total;
});
// Operations
self.addSeat = function () {
self.seats.push(new SeatReservation("", self.availableMeals[0]));
}
self.removeSeat = function (seat) { self.seats.remove(seat) }
}
ko.applyBindings(new ReservationsViewModel(), document.getElementById('food'));
When I run this the console logs the correct length (the ib variable), but the css class does not change.
Thank you for your help!
Where you have this line:
var ib = self.name.length;
You should be doing this:
var ib = self.name().length;
This seems to be working just fine when I test it in Chrome. Here is the jsFiddle:
http://jsfiddle.net/Xfv2g/
The only thing I can assume is that you are expecting it to change as they type. In order to do that you will have to change when the name field binds by putting the valueUpdate: 'afterkeydown' modifier to the value binding.
Here is the same fiddle with that being the only difference.
http://jsfiddle.net/Xfv2g/1/