Knockout disabling check boxes within a for loop upon change - checkbox

I have a list of check boxes in an observable array and I want to control the enabling and disabling of the check boxes when they are selected, per row. For example, when entering for the first time in the dialog, only the "Copy Form" and "Unlink" would be enabled. If "Copy Form" is checked, then the "Workflow" and "Reporting" would be enabled, but the "Unlink" we would be disabled. If "Unlink" is checked, then all other check boxes would be cleared of values and disabled.
Here is a screen shot of what I am trying to accomplish:
The code (removed some stuff that just complicates what I am trying to describe):
Html:
<tbody data-bind="foreach: SubAccountsToCopy()">
<tr>
<td class="col-sm-4" data-bind="text: linkedAccountName"></td>
<td class="col-sm-1" data-bind="text: linkedVersion"></td>
<td class="col-sm-1" data-bind="text: version"></td>
<td>
<input style="vertical-align: middle" id="copyForm" type="checkbox" data-bind="checked: copyForm, attr: { 'id': 'copyForm' + $index()}">
<label data-bind="attr: { 'for': 'copyForm' + $index()}">Copy Form</label>
</td>
<td title="Also copy the Form Workflow " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: copyWorkflow, attr: { 'id': 'copyWorkflow' + $index()}" />
<label data-bind="attr: { 'for': 'copyWorkflow' + $index()}">Workflow</label>
</td>
<td title="Also copy the Report Settings " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: copyReportSettings, attr: { 'id': 'copyReportSettings' + $index()}" />
<label data-bind="attr: { 'for': 'copyReportSettings' + $index()}">Reports</label>
</td>
<td title="Will unlink the SubAccount form from the Master Account " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: unlink, attr: { 'id': 'unlink' + $index()}" />
<label data-bind="attr: { 'for': 'unlink' + $index()}">Unlink</label>
</td>
</tr>
The javascript side is an JSON array mapped to the observable.

So the solution was a bit easier than I thought. Since all the checkboxes are observables, they react to changes, so you can use them in the logic:
<tbody data-bind="foreach: SubAccountsToCopy()">
<tr>
<td class="col-sm-4" data-bind="text: linkedAccountName"></td>
<td class="col-sm-1" data-bind="text: linkedVersion"></td>
<td class="col-sm-1" data-bind="text: version"></td>
<td title="Copy latest version of the form to this SubAccount" style="width:120px;">
<input style="vertical-align: middle" id="copyForm" type="checkbox" data-bind="checked: copyForm, disable: unlink, attr: { 'id': 'copyForm' + $index()}">
<label data-bind=" disable: unlink, style: {color: unlink() ? 'lightgray' : 'black'}, attr: { 'for': 'copyForm' + $index()}">Copy Form</label>
</td>
<td title="Also copy the Form Workflow " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: copyWorkflow, enable: copyForm, attr: { 'id': 'copyWorkflow' + $index()}" />
<label data-bind="style: {color: copyForm() ? 'black' : 'lightgray'}, attr: { 'for': 'copyWorkflow' + $index()}">Workflow</label>
</td>
<td title="Also copy the Report Settings " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: copyReportSettings, enable: copyForm, attr: { 'id': 'copyReportSettings' + $index()}" />
<label data-bind="style: {color: copyForm() ? 'black' : 'lightgray'}, attr: { 'for': 'copyReportSettings' + $index()}">Reports</label>
</td>
<td title="Will unlink the SubAccount form from the Master Account " style="width:100px;">
<input style="vertical-align: middle" type="checkbox" data-bind="checked: unlink, disable: copyForm, attr: { 'id': 'unlink' + $index()}" />
<label data-bind="style: {color: copyForm() ? 'lightgray' : 'black'}, attr: { 'for': 'unlink' + $index()}">Unlink</label>
</td>
</tr>

Related

React - How to check/uncheck checkboxes in a loop whose values come from redux store

I am trying to build a Notification settings via React and Redux where my against each email address I have few checkboxes say something in the below format.
import React from 'react'
export class NotificationSettings extends React.Component {
constructor(props) {
super(props);
this.getEmailUserRows = this.getEmailUserRows.bind(this)
}
getEmailUserRows() {
let _this = this
let emailRows = this.props.emailRows
let emailTemplate = emailRows.map((row) => {
return (
<tr key={row.email}>
<td height="70">
<span class="txt-limit">
<small>{row.email}</small>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={row.email+"sttng1"}
name={row.email+"sttng1"}
type="checkbox"/>
<label for="sttng1"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={row.email+"sttng2"}
name={row.email+"sttng2"}
type="checkbox"/>
<label for="sttng2"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={row.email+"sttng3"}
name={row.email+"sttng3"}
type="checkbox"/>
<label for="sttng3"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={row.email+"sttng4"}
name={row.email+"sttng4"}
type="checkbox"/>
<label for="sttng4"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={row.email+"sttng5"}
name={row.email+"sttng5"}
type="checkbox"
/>
<label for="sttng5"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="icon-delete"></span>
</td>
</tr>
)
})
return emailTemplate
}
render() {
return (
<div class="accordian-container open">
<div class="webhook-dtl">
<h4>Notification Settings</h4>
<table
width="100%"
border="0"
cellSpacing="0"
cellPadding="0"
class="transaction-detail">
<tbody>
<tr class="tbl-hdng">
<td width="24%" height="52" align="left">Email ID</td>
<td width="19%" class="no-spc">Transactional<br/>Emails</td>
<td width="13%" class="no-spc">Settlement<br/>Emails</td>
<td width="12%" class="no-spc">CRM<br/>Emails</td>
<td width="12%" class="no-spc">Onboarding<br/>Emails</td>
<td width="10%" class="no-spc">Other<br/>Emails</td>
<td width="10%" class="no-spc">Action</td>
</tr>
{this.getEmailUserRows()}
</tbody>
</table><br/>
<br/>
<button class="cmn-btn right">ADD MORE</button>
</div>
</div>
)
}
}
export default NotificationSettings
My JSON that is stored in the redux store:
{
"status": 0,
"rows": 0,
"message": "Merchant Details returned successfully",
"result": [
{
"email": "dashboard2#yopmail.com",
"emailCategoryList": {
"crmEmails": true,
"settlementEmails": true,
"transactionalEmails": true,
"onboardingEmails": true,
"otherEmails": true
},
"isMerchantBusinessEmail": true
},
{
"email": "vinikaty#gmail.com",
"emailCategoryList": {
"crmEmails": true,
"settlementEmails": false,
"transactionalEmails": false,
"onboardingEmails": true,
"otherEmails": true
},
"isMerchantBusinessEmail": false
}
],
"errorCode": null,
"guid": null
}
Pleae help me check/uncheck checkboxes in React not able to figure out what would be the best approach.
EDIT:
Made changes as suggested:
`import React from 'react';
let NotificationSettingRow = (props) => {
let { emailRowData } = props
const toggleCheckbox = () => {
console.log("Yay")
}
return (
<tr key={emailRowData.email}>
<td height="70">
<span class="txt-limit">
<small>{emailRowData.email}</small>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={emailRowData.email+"sttng1"}
name={emailRowData.email+"sttng1"}
{...(emailRowData.emailCategoryList.transactionalEmails ? {checked: true} : {}) }
onChange={toggleCheckbox}
type="checkbox"/>
<label for="sttng1"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={emailRowData.email+"sttng2"}
name={emailRowData.email+"sttng2"}
type="checkbox"/>
<label for="sttng2"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={emailRowData.email+"sttng3"}
name={emailRowData.email+"sttng3"}
type="checkbox"/>
<label for="sttng3"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={emailRowData.email+"sttng4"}
name={emailRowData.email+"sttng4"}
type="checkbox"/>
<label for="sttng4"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="pure-checkbox tog-check">
<input
id={emailRowData.email+"sttng5"}
name={emailRowData.email+"sttng5"}
type="checkbox"
/>
<label for="sttng5"></label>
</span>
</td>
<td class="no-spc" height="70">
<span class="icon-delete"></span>
</td>
</tr>
)
}
export default NotificationSettingRow`
However i am unable to check/uncheck checkboxes. Please help
Look at he last line in input, it basically evaluates if email in current row is in particular category, and if yes it renders checked=true, otherwise renders nothing
<input
id={row.email+"sttng1"}
name={row.email+"sttng1"}
type="checkbox"
{...(row.emailCategoryList.crmEmails ? {checked: true} : {}) }
/>
While you are at it you could define your component that would be used like:
<MyMailCheck row={row} idPrefix="sttng1" rowKey="crmEmails"/>
to avoid typing pretty much the same code for each email category.
Now how to handle checking and unchecking by the user. You need action that will be fired by the onClick for each checkbox. Something along these lines:
const emailCategoryClick = (email, category) => ({
type: 'EMAIL_CATEGORY_CLICK',
email,
category
})
And you need suitable reducer to recognize this action, and update state accordingly.
Lastly, you need to wire your checkboxes to dispatch correct emailCategoryClick actions. To do so, you should connect your component to get access to dispatch method from store. Something like:
export default connect(
(state) => ({}),
(dispatch) => ({catClick: (email, cat) => () => {dispatch(emailCategoryClick(email, cat))} })
)(NotificationSettings)
and in your checkbox you would add onClick handler as in:
<input
id={row.email+"sttng1"}
name={row.email+"sttng1"}
type="checkbox"
{...(row.emailCategoryList.crmEmails ? {checked: true} : {}) }
onCLick={catClick(row.email, "crmEmails")}
/>

ng-repeat errors. Can't read property of undefined

I have two errors saying: Cannot read property 'active' of undefined and Cannot read property 'boss' of undefined while I'm trying to use ng-repeat over my array of users.
In the controller I'm using the following code:
$scope.users = [
{
id: 1,
name: 'John',
birthday: '06.07.2008',
city: 'Budapest',
active: false,
boss: false
},
{
id: 2,
name: 'Mary',
birthday: '01.02.2003',
city: 'Berlin',
active: false,
boss: true
},
{
id: 3,
name: 'James',
birthday: '04.05.2006',
city: 'Vienna',
active: false,
boss: false
}
];
$scope.isActive = function (id) {
return $scope.users[id].active;
}
$scope.isBoss = function (id) {
console.log($scope.users[id]);
return $scope.users[id].boss;
}
In the view I have following code:
<thead>
<tr>
<th>#</th>
<th>Username</th>
<th>Birthday</th>
<th>City</th>
<th>Active</th>
<th>Boss</th>
</tr>
</thead>
<tbody>
<div>
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.birthday}}</td>
<td>{{user.city}}</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }">
</td>
</tr>
</div>
</tbody>
At the end it prints the table in the right way but also throws those errors. Did I miss something?
Also here's rendered result:
<tbody>
<!-- ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">1</td>
<td class="ng-binding">John</td>
<td class="ng-binding">06.07.2008</td>
<td class="ng-binding">Budapest</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }" checked="checked">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }" checked="checked">
</td>
</tr>
<!-- end ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">2</td>
<td class="ng-binding">Mary</td>
<td class="ng-binding">01.02.2003</td>
<td class="ng-binding">Berlin</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }" checked="checked">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }" checked="checked">
</td>
</tr>
<!-- end ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">3</td>
<td class="ng-binding">James</td>
<td class="ng-binding">04.05.2006</td>
<td class="ng-binding">Vienna</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }">
</td>
</tr>
<!-- end ngRepeat: user in users -->
</tbody>
That's because your isActive and isBoss functions are being passed user.id. I observed your user.id starts from id 1, meanwhile in these functions, you're trying to access the $scope.users using the indexes passed in. What happens is that, for example, a user.id of 3 in your isActive function would try to access $scope.users[3].active. However, there's actually no index 3 (representing the fourth item in the $scope.users array, which is undefined)
Change your ..isActive(user.id) to ...isActive($index) and your ...isBoss(user.id) to ...isBoss($index)

AngularJS performance in Firefox

I am building an application with AngularJS, and I am facing problems with the firefox. I think it's because I use multiple ng-repeat inside others ng-repeat, I have already tried almost all what I found in stackoverflow and forums.
I have a big table with multiple loops, this is what the table looks like :
<table class="booking-table table table-condensed mergeCells"
id="booking-table" ng-if="bookingSelected.accounts.length != 0">
<thead>
<tr>
<th colspan="10" class="transparent separator"></th>
<th colspan="2" style="border-top: 1px solid #000 !important;">OPPORTUNITY
DEFINITION</th>
<td class="separator"></td>
</tr>
<tr>
<th colspan="2">REGION</th>
<th>COUNTRY</th>
<th>MARKETS</th>
<th>SERVICE</th>
<th>TYPE</th>
<th>CUSTOMER</th>
<th>BDO Ref</th>
<th style="width: 100px !important;">Probability %</th>
<th style="width: 110px !important;">Booking Revenue</th>
<th class="gray" style="width: 10px !important;">Nb</th>
<th class="gray" style="width: 221px !important;">Name</th>
<th class="separator"></th>
<th class="transparent po-info left"
style="text-align: center;">PO Number</th>
<th class="transparent po-info left"
style="width: 80px !important; text-align: center;"
colspan="2">PO Amount</th>
</tr>
</thead>
<tbody bindonce
ng-repeat="account in bookingSelected.accounts track by account.id">
<!-- Booking line -->
<tr class="gray">
<td rowspan="2" colspan="10" class="separator"><span
class="remove-opp button-hover" ng-if="isNotReadOnlyAdmin()"
ng-click="addOpportunity(account)"><i
class="fa fa-plus"></i> Add</span><span
class="remove-opp button-hover readOnlyButtons"
ng-if="isReadOnlyAdmin()"><i class="fa fa-plus"></i>
Add</span> <span class="remove-opp button-hover"
ng-if="account.id == null && currentUser.isAdministrator"
ng-click="removeAccount(account)"><i
class="fa fa-times"></i> Remove Account</span></td>
<td colspan="2">BOOKING GOALS</td>
<td rowspan="2" class="separator"></td>
<td class="po-info"></td>
<td class="transparent right po-info input number" colspan="2">
<input ng-model-options="{ debounce: 600 }"
ng-model="account.bookingGoals" class="input-number"
ng-change="totalAccountOpportunity(account)"></input> <span
class="suffix">€</span>
</td>
</tr>
<tr class="gray">
<td colspan="2" class="transparent text-red">REMAINING
BOOKING GOALS proba weight</td>
<td class="po-info"></td>
<td class="transparent right po-info input"
ng-class="{'text-red' : account.remaining > 0, 'text-green' : account.remaining <= 0}"
colspan="2">
<div>
<span> {{ account.remaining | number }} € </span>
</div>
</td>
</tr>
<!-- Account -->
<tr class="orange" bindonce
ng-repeat-start="opportunity in account.opportunities track by opportunity.id">
<td class="remove-opp" ng-if="showRemoveButton(opportunity)"
ng-click="removeOpportunity(account, opportunity)">
<center>
<i class="fa fa-times"></i>
</center>
</td>
<td class="center input" ng-click="makeRowActive(null)"
ng-if="showRemoveButton(opportunity)"><input
ng-model-options="{ debounce: 600 }" uib-popover="REGION"
popover-trigger="'focus'" type="text" ng-model="account.title"></td>
<td class="center input" colspan="2"
ng-click="makeRowActive(null)"
ng-if="!showRemoveButton(opportunity)"><input
ng-model-options="{ debounce: 600 }" uib-popover="REGION"
popover-trigger="'focus'" type="text" ng-model="account.title"></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="COUNTRY" popover-trigger="'focus'"
ng-model="opportunity.country"
ng-options="country as country.libelle for country in countries track by country.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="MARKET" popover-trigger="'focus'"
ng-model="opportunity.market"
ng-options="market as market.libelle for market in markets track by market.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="SERVICE" popover-trigger="'focus'"
ng-model="opportunity.service"
ng-options="service as service.libelle for service in services track by service.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="TYPE" popover-trigger="'focus'"
ng-model="opportunity.type"
ng-options="type as type.libelle for type in types track by type.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="CUSTOMER" popover-trigger="'focus'"
ng-model="opportunity.client"
ng-options="customer as customer.raisonSociale for customer in customers track by customer.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)">{{
opportunity.bdoNumber }}</td>
<td class="right input"
ng-class="{'green' : opportunity.probability.value >= 90, 'orange' : opportunity.probability.value == 60, 'red' : opportunity.probability.value == 30, 'gray' : opportunity.probability.value < 30}"
ng-click="makeRowActive(null)"><select
uib-popover="Probability %" popover-trigger="'focus'"
ng-model="opportunity.probability"
ng-change="updatePoAmmountOpportunity(account, opportunity)"
ng-options="probability as probability.libelle for probability in probabilities track by probability.id">
</select></td>
<td class="right input" ng-click="makeRowActive(null)">
<div ng-if="showPoAmmount(opportunity)">
<span> {{ opportunity.poAmmount | number }} € </span>
</div>
</td>
<td class="input" ng-click="makeRowActive(null)"
style="width: 30px;"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="Nb" popover-trigger="'focus'"
ng-model="opportunity.nb"></td>
<td class="input" ng-click="makeRowActive(null)"
style="width: 300px !important;"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="OPPORTUNITY DEFINITION" popover-trigger="'focus'"
ng-model="opportunity.definition"></td>
<td class="separator"></td>
<td class="center po-info input" ng-click="makeRowActive(null)">
<input ng-model-options="{ debounce: 600 }" type="text"
ng-model="opportunity.revenue" uib-popover="REVENUE"
popover-trigger="'focus'" class="input-number"
ng-change="updatePoAmmountOpportunity(account, opportunity)">
</td>
<td class="right po-info input" ng-click="makeRowActive(null)">
<div ng-if="showPoAmmount(opportunity)">
<span> {{ opportunity.poAmmount | number }} € </span>
</div>
</td>
<td class="remove-opp" title="Add opportunity"
ng-if="isNotReadOnly()"
ng-click="addOpportunityChildren(opportunity)">
<center>
<i class="fa fa-plus"></i> Add
</center>
</td>
<td class="remove-opp readOnlyButtons"
title="Add opportunity (disabled)" ng-if="isReadOnly()">
<center>
<i class="fa fa-plus"></i> Add
</center>
</td>
</tr>
<!-- Opportunities -->
<tr bindonce
ng-repeat="opp in opportunity.opportunities track by opp.id"
ng-class="{'active' : opp == activeOpp}">
<td class="center input rowSpan" colspan="2"
test="{{ account.title }}" ng-click="makeRowActive(opp)">
{{ account.title }}</td>
<td class="input" ng-click="makeRowActive(null)"><select
ng-model="opp.country" uib-popover="COUNTRY"
popover-trigger="'focus'"
ng-options="country as country.libelle for country in countries track by country.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="MARKET" popover-trigger="'focus'"
ng-model="opp.market"
ng-options="market as market.libelle for market in markets track by market.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="SERVICE" popover-trigger="'focus'"
ng-model="opp.service"
ng-options="service as service.libelle for service in services track by service.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="TYPE" popover-trigger="'focus'"
ng-model="opp.type"
ng-options="type as type.libelle for type in types track by type.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="CUSTOMER" popover-trigger="'focus'"
ng-model="opp.client"
ng-options="customer as customer.raisonSociale for customer in customers track by customer.id">
</select></td>
<td class="input" style="padding-left: 5px !important;"
ng-class="{'redB' : opp.bdoNumber == null || opp.bdoNumber == ''}"
ng-click="makeRowActive(opp)">{{ opp.bdoNumber }}</td>
<td class="right input"
ng-class="{'green' : opp.probability.value >= 90, 'orange' : opp.probability.value == 60, 'red' : opp.probability.value == 30, 'gray' : opp.probability.value < 30}"
ng-click="makeRowActive(opp)"><select
uib-popover="Probability %" popover-trigger="'focus'"
ng-model="opp.probability"
ng-change="updatePoAmmountOpportunityChild(opp, account)"
ng-options="probability as probability.libelle for probability in probabilities track by probability.id">
</select></td>
<td class="right input" ng-click="makeRowActive(opp)">
<div>
<span> {{ opp.poAmmount | number }} € </span>
</div>
</td>
<td style="width: 30px;" class="input"
ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="Nb" popover-trigger="'focus'" uib-popover="Nb"
popover-trigger="'focus'" ng-model="opp.nb"></td>
<td class="input" ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }"
uib-popover="OPPORTUNITY DEFINITION" popover-trigger="'focus'"
type="text" ng-model="opp.definition"></td>
<td class="separator"></td>
<td class="center po-info input" ng-click="makeRowActive(opp)">
<input ng-model-options="{ debounce: 600 }" type="text"
ng-model="opp.po" uib-popover="PO Number"
popover-trigger="'focus'">
</td>
<td class="right po-info input number"
ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }" uib-popover="PO Amount"
popover-trigger="'focus'" ng-model="opp.poAmmount"
class="input-number"
ng-change="updatePoAmmountOpportunityChild(opp, account)"></input>
<span class="suffix">€</span></td>
<td ng-if="isNotReadOnly()"><i
class="fa fa-chevron-up remove-opp" title="Move up"
ng-click="opportunityToUp(opportunity, opp)"></i> <i
class="fa fa-chevron-down remove-opp" title="Move down"
ng-click="opportunityToDown(opportunity, opp)"></i> <i
class="fa fa-times remove-opp" title="Remove opportunity"
ng-if="showRemoveButton(opp)"
ng-click="removeOpportunityChildren(opportunity, opp, account)"></i>
<i class="fa fa-clone remove-opp"
title="Duplicate opportunity"
ng-click="duplicateOpportunityChildren(opportunity, opp)"></i>
<i class="fa fa-eye remove-opp" title="Show history"
ng-click="showHistory(account, opportunity, opp)"
data-toggle="modal" data-target="#opportunityHistory"></i></td>
<td ng-if="isReadOnly()" class="readOnlyButtons"><i
class="fa fa-chevron-up remove-opp" title="Move up (disabled)"></i>
<i class="fa fa-chevron-down remove-opp"
title="Move down (disabled)"></i> <i
class="fa fa-times remove-opp"
title="Remove opportunity (disabled)"></i> <i
class="fa fa-clone remove-opp"
title="Duplicate opportunity (disabled)"></i> <i
class="fa fa-eye remove-opp" title="Show history (disabled)"></i></td>
</tr>
<!-- Total -->
<tr class="total" ng-if="$last">
<td colspan="10" class="separator"></td>
<td colspan="2">TOTAL {{ account.title }}</td>
<td class="separator"></td>
<td></td>
<td class="center" colspan="2">
<div>
<span> {{ opportunity.total }} € </span>
</div>
</td>
</tr>
<tr ng-if="($index + 1) < bookingSelected.accounts.length"
ng-repeat-end>
<td colspan="16"
style="height: 10px !important; border: none !important; background: #fff !important;"></td>
</tr>
</tbody>
<tr class="separator"></tr>
<tr class="total">
<td colspan="12">TOTAL SUM</td>
<td class="separator"></td>
<td class="total-sum"></td>
<td class="center total-sum" colspan="2">
<div>
<span> {{ totalBooking | number }} € </span>
</div>
</td>
</tr>
</table>
I am using now the bindonce module.
In Google Chrome I have no problems with the performance, it's only in Mozilla firefox (I tried multiple version of this browser, all have the same issue).
Bellow is a snapshot of the firefox performance tool :
UPDATED
<table class="booking-table table table-condensed mergeCells"
id="booking-table" ng-if="::bookingSelected.accounts.length">
<thead>
<tr>
<th colspan="10" class="transparent separator"></th>
<th colspan="2" style="border-top: 1px solid #000 !important;">OPPORTUNITY
DEFINITION</th>
<td class="separator"></td>
</tr>
<tr>
<th colspan="2">REGION</th>
<th>COUNTRY</th>
<th>MARKETS</th>
<th>SERVICE</th>
<th>TYPE</th>
<th>CUSTOMER</th>
<th>BDO Ref</th>
<th style="width: 100px !important;">Probability %</th>
<th style="width: 110px !important;">Booking Revenue</th>
<th class="gray" style="width: 10px !important;">Nb</th>
<th class="gray" style="width: 221px !important;">Name</th>
<th class="separator"></th>
<th class="transparent po-info left"
style="text-align: center;">PO Number</th>
<th class="transparent po-info left"
style="width: 80px !important; text-align: center;"
colspan="2">PO Amount</th>
</tr>
</thead>
<tbody bindonce
ng-repeat="account in bookingSelected.accounts track by $index">
<!-- Booking line -->
<tr class="gray">
<td rowspan="2" colspan="10" class="separator"><span
class="remove-opp button-hover" ng-if="isNotReadOnlyAdmin()"
ng-click="addOpportunity(account)"><i
class="fa fa-plus"></i> Add</span><span
class="remove-opp button-hover readOnlyButtons"
ng-if="isReadOnlyAdmin()"><i class="fa fa-plus"></i>
Add</span> <span class="remove-opp button-hover"
ng-if="account.id == null && currentUser.isAdministrator"
ng-click="removeAccount(account)"><i
class="fa fa-times"></i> Remove Account</span></td>
<td colspan="2">BOOKING GOALS</td>
<td rowspan="2" class="separator"></td>
<td class="po-info"></td>
<td class="transparent right po-info input number" colspan="2">
<input ng-model-options="{ debounce: 600 }"
ng-model="::account.bookingGoals" class="input-number"
ng-change="::totalAccountOpportunity(account)"></input> <span
class="suffix">€</span>
</td>
</tr>
<tr class="gray">
<td colspan="2" class="transparent text-red">REMAINING
BOOKING GOALS proba weight</td>
<td class="po-info"></td>
<td class="transparent right po-info input"
ng-class="{'text-red' : account.remaining > 0, 'text-green' : account.remaining <= 0}"
colspan="2">
<div>
<span> {{ ::(account.remaining | number) }} € </span>
</div>
</td>
</tr>
<!-- Account -->
<tr class="orange" bindonce
ng-repeat-start="opportunity in account.opportunities track by $index">
<td class="remove-opp" ng-if="::showRemoveButton(opportunity)"
ng-click="removeOpportunity(account, opportunity)">
<center>
<i class="fa fa-times"></i>
</center>
</td>
<td class="center input" ng-click="makeRowActive(null)"
ng-if="::showRemoveButton(opportunity)"><input
ng-model-options="{ debounce: 600 }" uib-popover="REGION"
popover-trigger="'focus'" type="text"
ng-model="::account.title"></td>
<td class="center input" colspan="2"
ng-click="makeRowActive(null)"
ng-if="::(!showRemoveButton(opportunity))"><input
ng-model-options="{ debounce: 600 }" uib-popover="REGION"
popover-trigger="'focus'" type="text"
ng-model="::account.title"></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="COUNTRY" popover-trigger="'focus'"
ng-model="::opportunity.country"
ng-options="country as country.libelle for country in countries track by country.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="MARKET" popover-trigger="'focus'"
ng-model="::opportunity.market"
ng-options="market as market.libelle for market in markets track by market.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="SERVICE" popover-trigger="'focus'"
ng-model="::opportunity.service"
ng-options="service as service.libelle for service in services track by service.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="TYPE" popover-trigger="'focus'"
ng-model="::opportunity.type"
ng-options="type as type.libelle for type in types track by type.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="CUSTOMER" popover-trigger="'focus'"
ng-model="::opportunity.client"
ng-options="customer as customer.raisonSociale for customer in customers track by customer.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)">{{
::opportunity.bdoNumber }}</td>
<td class="right input"
ng-class="{'green' : opportunity.probability.value >= 90, 'orange' : opportunity.probability.value == 60, 'red' : opportunity.probability.value == 30, 'gray' : opportunity.probability.value < 30}"
ng-click="makeRowActive(null)"><select
uib-popover="Probability %" popover-trigger="'focus'"
ng-model="::opportunity.probability"
ng-change="updatePoAmmountOpportunity(account, opportunity)"
ng-options="probability as probability.libelle for probability in probabilities track by probability.id">
</select></td>
<td class="right input" ng-click="makeRowActive(null)">
<div ng-if="::showPoAmmount(opportunity)">
<span> {{ ::(opportunity.poAmmount | number) }} € </span>
</div>
</td>
<td class="input" ng-click="makeRowActive(null)"
style="width: 30px;"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="Nb" popover-trigger="'focus'"
ng-model="::opportunity.nb"></td>
<td class="input" ng-click="makeRowActive(null)"
style="width: 300px !important;"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="OPPORTUNITY DEFINITION" popover-trigger="'focus'"
ng-model="::opportunity.definition"></td>
<td class="separator"></td>
<td class="center po-info input" ng-click="makeRowActive(null)">
<input ng-model-options="{ debounce: 600 }" type="text"
ng-model="::opportunity.revenue" uib-popover="REVENUE"
popover-trigger="'focus'" class="input-number"
ng-change="updatePoAmmountOpportunity(account, opportunity)">
</td>
<td class="right po-info input" ng-click="makeRowActive(null)">
<div ng-if="::showPoAmmount(opportunity)">
<span> {{ opportunity.poAmmount | number }} € </span>
</div>
</td>
<td class="remove-opp" title="Add opportunity"
ng-if="::isNotReadOnly()"
ng-click="addOpportunityChildren(opportunity)">
<center>
<i class="fa fa-plus"></i> Add
</center>
</td>
<td class="remove-opp readOnlyButtons"
title="Add opportunity (disabled)" ng-if="::isReadOnly()">
<center>
<i class="fa fa-plus"></i> Add
</center>
</td>
</tr>
<!-- Opportunities -->
<tr bindonce
ng-repeat="opp in opportunity.opportunities track by $index"
ng-class="{'active' : opp == activeOpp}">
<td class="center input" colspan="2"
ng-click="makeRowActive(opp)">{{ ::account.title }}</td>
<td class="input" ng-click="makeRowActive(null)"><select
ng-model="::opp.country" uib-popover="COUNTRY"
popover-trigger="'focus'"
ng-options="country as country.libelle for country in countries track by country.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="MARKET" popover-trigger="'focus'"
ng-model="::opp.market"
ng-options="market as market.libelle for market in markets track by market.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="SERVICE" popover-trigger="'focus'"
ng-model="::opp.service"
ng-options="service as service.libelle for service in services track by service.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="TYPE" popover-trigger="'focus'"
ng-model="::opp.type"
ng-options="type as type.libelle for type in types track by type.id">
</select></td>
<td class="input" ng-click="makeRowActive(null)"><select
uib-popover="CUSTOMER" popover-trigger="'focus'"
ng-model="::opp.client"
ng-options="customer as customer.raisonSociale for customer in customers track by customer.id">
</select></td>
<td class="input" style="padding-left: 5px !important;"
ng-class="{'redB' : opp.bdoNumber == null || opp.bdoNumber == ''}"
ng-click="makeRowActive(opp)">{{ opp.bdoNumber }}</td>
<td class="right input"
ng-class="{'green' : opp.probability.value >= 90, 'orange' : opp.probability.value == 60, 'red' : opp.probability.value == 30, 'gray' : opp.probability.value < 30}"
ng-click="makeRowActive(opp)"><select
uib-popover="Probability %" popover-trigger="'focus'"
ng-model="::opp.probability"
ng-change="updatePoAmmountOpportunityChild(opp, account)"
ng-options="probability as probability.libelle for probability in probabilities track by probability.id">
</select></td>
<td class="right input" ng-click="makeRowActive(opp)">
<div>
<span> {{ opp.poAmmount | number }} € </span>
</div>
</td>
<td style="width: 30px;" class="input"
ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }" type="text"
uib-popover="Nb" popover-trigger="'focus'" uib-popover="Nb"
popover-trigger="'focus'" ng-model="::opp.nb"></td>
<td class="input" ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }"
uib-popover="OPPORTUNITY DEFINITION" popover-trigger="'focus'"
type="text" ng-model="::opp.definition"></td>
<td class="separator"></td>
<td class="center po-info input" ng-click="makeRowActive(opp)">
<input ng-model-options="{ debounce: 600 }" type="text"
ng-model="::opp.po" uib-popover="PO Number"
popover-trigger="'focus'">
</td>
<td class="right po-info input number"
ng-click="makeRowActive(opp)"><input
ng-model-options="{ debounce: 600 }" uib-popover="PO Amount"
popover-trigger="'focus'" ng-model="::opp.poAmmount"
class="input-number"
ng-change="updatePoAmmountOpportunityChild(opp, account)"></input>
<span class="suffix">€</span></td>
<td ng-if="::isNotReadOnly()"><i
class="fa fa-chevron-up remove-opp" title="Move up"
ng-click="opportunityToUp(opportunity, opp)"></i> <i
class="fa fa-chevron-down remove-opp" title="Move down"
ng-click="opportunityToDown(opportunity, opp)"></i> <i
class="fa fa-times remove-opp" title="Remove opportunity"
ng-if="::showRemoveButton(opp)"
ng-click="removeOpportunityChildren(opportunity, opp, account)"></i>
<i class="fa fa-clone remove-opp"
title="Duplicate opportunity"
ng-click="duplicateOpportunityChildren(opportunity, opp)"></i>
<i class="fa fa-eye remove-opp" title="Show history"
ng-click="showHistory(account, opportunity, opp)"
data-toggle="modal" data-target="#opportunityHistory"></i></td>
<td ng-if="::isReadOnly()" class="readOnlyButtons"><i
class="fa fa-chevron-up remove-opp" title="Move up (disabled)"></i>
<i class="fa fa-chevron-down remove-opp"
title="Move down (disabled)"></i> <i
class="fa fa-times remove-opp"
title="Remove opportunity (disabled)"></i> <i
class="fa fa-clone remove-opp"
title="Duplicate opportunity (disabled)"></i> <i
class="fa fa-eye remove-opp" title="Show history (disabled)"></i></td>
</tr>
<!-- Total -->
<tr class="total" ng-if="::$last">
<td colspan="10" class="separator"></td>
<td colspan="2">TOTAL {{ account.title }}</td>
<td class="separator"></td>
<td></td>
<td class="center" colspan="2">
<div>
<span> {{ opportunity.total }} € </span>
</div>
</td>
</tr>
<tr ng-if="::(($index + 1) < bookingSelected.accounts.length)"
ng-repeat-end>
<td colspan="16"
style="height: 10px !important; border: none !important; background: #fff !important;"></td>
</tr>
</tbody>
<tr class="separator"></tr>
<tr class="total">
<td colspan="12">TOTAL SUM</td>
<td class="separator"></td>
<td class="total-sum"></td>
<td class="center total-sum" colspan="2">
<div>
<span> {{ ::(totalBooking | number) }} € </span>
</div>
</td>
</tr>
</table>
try to use this in all app:
{{ ::(opportunity.poAmmount | number) }}
function in ng-if and bg-class is a pure evil
ng-if="::showRemoveButton(opportunity)"
refactor ng-if="bookingSelected.accounts.length != 0" => ng-if="::bookingSelected.accounts.length"
but remember that bind-once inside ng-if is very fragile/ you should return undefiend from function if data do not get yet from server

angular-strap datepicker disable-dates

Using angular-strap v2.2.1, I have a scenario where I have list of periods every period use min-date and max-date attribute and when set a period in the change of end date ,I should disable this period here is the html :
<div class="row">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th colspan="4" style="border: none"></th>
<th colspan="10" class="text-center">Series Closed</th>
</tr>
<tr>
<th>Period</th>
<th>Period Name</th>
<th>Start Date</th>
<th>End Date</th>
<th>Financial</th>
<th>Sales</th>
<th>Purchasing</th>
<th>Inventory</th>
<th>Payroll</th>
<th>Manufacturing</th>
<th>Expense Management</th>
<th>POS</th>
<th>Bank</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="period in AllPeriods">
<td>1</td>
<td class="col-md-3">
<input type="text" id="PeriodName{{$index}}" class="form-control input-sm"
placeholder="Period Name" ng-model="period.PeriodName">
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" id="StartDate{{$index}}" class="form-control" ng-model="period.StartDate"
data-date-format="dd/MM/yyyy" data-max-date="{{period.EndDate}}"
data-disabled-dates="{{unavailableDates}}"
autoclose="true"
placeholder="Start Date" bs-datepicker>
<span class="input-group-addon">
<i class="fa fa-calendar"></i>
</span>
</div>
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" id="EndDate{{$index}}" class="form-control" ng-model="period.EndDate"
data-date-format="dd/MM/yyyy" data-min-date="{{period.StartDate}}"
data-disabled-dates="{{unavailableDates}}"
autoclose="true"
placeholder="End Date" ng-change="DisableDate(period.StartDate,period.EndDate)" bs-datepicker>
<span class="input-group-addon">
<i class="fa fa-calendar"></i>
</span>
</div>
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsClosed{{$index}}" ng-model="period.IsClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsSalesClosed{{$index}}" ng-model="period.IsSalesClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsPurchaseClosed{{$index}}" ng-model="period.IsPurchaseClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsInventoryClosed{{$index}}" ng-model="period.IsInventoryClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="PayrollClosed{{$index}}" ng-model="period.PayrollClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsManufacturingClosed{{$index}}" ng-model="period.IsManufacturingClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsExpenseManagementClosed{{$index}}" ng-model="period.IsExpenseManagementClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsPOSClosed{{$index}}" ng-model="period.IsPOSClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsBankClosed{{$index}}" ng-model="period.IsBankClosed" style="position:static;opacity:10;">
</td>
</tr>
</table>
</div>
</div>
in the JS :
$scope.AllPeriods = [];
$scope.NumberOfPeriodsChanged = function () {
$scope.AllPeriods = [];
var num = $("#Num").val();
for (var i = 0; i < num; i++) {
var temp = {
YearCode: '',
PeriodName: '',
StartDate: '',
EndDate: '',
IsClosed: '',
IsSalesClosed: '',
IsPurchaseClosed: '',
IsInventoryClosed: '',
PayrollClosed: '',
};
$scope.AllPeriods.push(temp);
}
};
$scope.unavailableDates = [];
$scope.DisableDate = function (start, end) {
$scope.unavailableDates.push({
start: new Date(start),
end: new Date(end)
});
};
i solved this problem by making two functions to return date_to and date_from :
$scope.ToCustomDate = function (index) {
if (index == 0) {
return;
}
var dt = new Date($scope.AllPeriods[index].StartDate);
dt.setDate(dt.getDate() + 1);
return dt;
};
$scope.FromCustomDate = function (index) {
if (index == 0) {
return;
}
var dt = new Date($scope.AllPeriods[index - 1].EndDate);
dt.setDate(dt.getDate() + 1);
return dt;
};
I have tried your example and it seems that it doesn't work dynamically, You can put the disabled dates in advance and add the next period when the user finish editing the first one, or you might forward your question as issue in angular-strap
btw you don't need brackets to set the disabled dates
data-disabled-dates="unavailableDates"
and you need to refactor your function to take index as it keep adding dates to the array
$scope.DisableDate = function( index, start, end ) {
if ( angular.isDate( start ) && angular.isDate( end ) ) {
$scope.unavailableDates[index] = {
start: new Date( start ).toISOString(),
end: new Date( end ).toISOString()
};
}
};

AngularJS Sort table columns

I have a table filter whichs show the content according to the user parameters, this is working perfectly but now I want to let the user filter according to each column.
This is the issue:
When you type "User" on the text input (Filter by columns" I want to only display the "User Column", if you type "Start Date" then only displays "Start Date column" I'm wondering if this is possible using filter option or how can I approach to this requirement.
Here's my code:
<div class="col-xs-10 grid-container">
<div class="row form-entry">
<div class="col-xs-3 input-container">
<input type="text" placeholder="Search in Grid" ng-model="searchFills"/>
</div>
<div class="col-xs-3 input-container">
<input type="text" placeholder="Filter by columns" />
</div>
</div>
<div class="col-xs-10 grid-container">
<div class="generic-grid">
<table class="table-bordered grid-table table-hover">
<thead>
<tr>
<th>id</th>
<th>User</th>
<th>Alt User</th>
<th>Creation Date</th>
<th>Start Date</th>
<th>Recieved Date</th>
<th>1</th>
<th>2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="fill in fills_list | filter:searchFills">
<td>
{{fill.id}}
</td>
<td>
{{fill.user}}
</td>
<td>
{{fill.useralt}}
</td>
<td>
{{fill.creationdate}}
</td>
<td>
{{fill.startdate}}
</td>
<td>
{{fill.recieveddate}}
</td>
<td>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</div>
</div>
You can add ng-model="columnFilter" to your input:
<input type="text" placeholder="Filter by columns" `ng-model="columnFilter"` />
Then addng-hide="columnFilter == 'Start Date'" to <td>{{fill.user}}</td>
Add ng-hide="columnFilter == 'User'" to <td>{{fill.startdate}}</td>
And add ng-hide="columnFilter == 'User' || columnFilter == 'Start Date'" to the rest of the <td>'s.
If you want to filter by column, then you need ng-repeat by columns. After that you can use the same filter that you are using for filtering rows
controller.js
controllers.controller("MainController", ["$scope", function($scope) {
return ["$scope", function ($scope) {
$scope.columns = [{
title: "id",
alias: "id"
}, {
title: "User",
alias: "user"
}, {
title: "Alt User",
alias: "useralt"
}, {
title: "Creation Date",
alias: "creationdate"
}, {
title: "Start Date",
alias: "startdate"
}, {
title: "Recieved Date",
alias: "recieveddate"
}];
}]);
template.html
<div ng-controller="MainController">
<div class="col-xs-10 grid-container">
<div class="row form-entry">
<div class="col-xs-3 input-container">
<input type="text" placeholder="Search in Grid" ng-model="searchFills" />
</div>
<div class="col-xs-3 input-container">
<input type="text" placeholder="Filter by columns" ng-model="searchColumn" />
</div>
</div>
<div class="col-xs-10 grid-container">
<div class="generic-grid">
<table class="table-bordered grid-table table-hover">
<thead>
<tr>
<th ng-repeat="column in columns | filter:searchColumn">{{column.title}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="fill in fills_list | filter:searchFills">
<td ng-repeat="column in columns | filter:searchColumn">{{fill[column.alias]}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
That will filter any column in a table.

Resources