How have I broken this Todo list in ReactJS code? - javascript

An earlier draft of code to handle a Todo list, with fewer features, works:
{
return 0;
}
});
return (
<div id="Todo">
<h1>Todo</h1>
<form onSubmit={that.handleSubmit}>
<table>
{table_rows}
<tfoot>
<textarea name='todo-textarea' id='todo-textarea'
onChange={that.onChange}></textarea><br />
<button>{'Add activity'}</button>
</tfoot>
</table>
</form>
</div>
);
}
});
My present version is getting an InvariantViolation:
react-with-addons.js:20237 Uncaught Error: Invariant Violation: findComponentRoot(..., .0.1.1.0.0:0:0.0:1.0): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a <tbody> when using tables, nesting tags like <form>, <p>, or <a>, or using non-SVG elements in an parent. Try inspecting the child nodes of the element with React ID ``.
The present code is:
var Todo = React.createClass(
{
mixins: [React.addons.LinkedStateMixin],
getInitialState: function()
{
var result = parse(initial_todo, {
'next_todo_index': 1,
'items': [],
'text': ''
});
return result;
},
handle_change: function(event)
{
var that = this;
var address = jQuery(event.target).attr('data-index').split('.', 2);
var identifier = parseInt(address[0], 10);
for(var candidate = 0; candidate < this.state.next_todo_index;
candidate += 1)
{
if (parseInt(jQuery(this.state.items[candidate]).attr('index'), 10)
=== identifier)
{
(this.state.items[candidate][address[1]] =
!this.state.items[candidate][address[1]]);
save('Todo', this.state);
}
}
that.render();
},
handleSubmit: function(event)
{
event.preventDefault();
var new_item = get_todo_item(this);
new_item.description = this.state.text;
this.state.items.unshift(new_item);
document.getElementById('todo-textarea').value = '';
save('Todo', this.state);
if (!one_shot)
{
one_shot = true;
}
// this.forceUpdate();
// React.render(<Todo />,
// document.getElementById('Todo'));
},
onChange: function(event)
{
this.setState({text: event.target.value});
},
render: function()
{
var that = this;
var table_rows = [];
var display_item_details = function(label, item)
{
var html_id = item.index + '.' + label;
return (
<td className={label} title={label}>
<input onChange={that.handle_change} data-index={html_id}
className={label} type="checkbox"
defaultChecked={item[label]} />
</td>
);
};
var display_item = function(item)
{
var rendered_nodes = [];
if (item['Completed'] || item['Delete'] || item['Invisible'])
{
return '';
}
else
{
for(var index = 0; index < todo_item_names.length;
index += 1)
{
rendered_nodes.push(
display_item_details(todo_item_names[index], item)
);
}
return (
<tr>{rendered_nodes}
<td className="description" dangerouslySetInnerHTML={{__html:
converter.makeHtml(item.description)}} /></tr>
);
}
};
table_rows.push(that.state.items.map(display_item));
table_rows.sort(function(a, b)
{
if (a.index > b.index)
{
return 1;
}
else if (b.index > a.index)
{
return -1;
}
else
{
return 0;
}
});
return (
<div id="Todo">
<h1>Todo</h1>
<form onSubmit={that.handleSubmit}>
<table>
<tbody>
{table_rows}
<tbody>
<tfoot>
<textarea name='todo-textarea' id='todo-textarea'
onChange={that.onChange}></textarea><br />
<button>{'Add activity'}</button>
</tfoot>
</table>
</form>
</div>
);
}
});
How have I broken this?

Do check through your html table structure. Other than the <tbody> fix, the usage of <tfoot> is also invalid markup.
The <tfoot> element can only contain <tr> tags inside.
i.e.
<tfoot>
<tr>
<td>
<textarea name='todo-textarea' id='todo-textarea'
onChange={that.onChange}></textarea><br />
<button>{'Add activity'}</button>
</td>
</tr>
</tfoot>

Related

Get checkbox values with different class name in the same div id - jquery mvc

I am trying to get the values of checkboxes which are in the same divid but have different class name.
<tr>
<td colspan="4" align="center">
<div id="divEntities" style="width:100%;height:150px;overflow-y:scroll;align:center;">
<table cellspacing="2" cellpadding="2" width="95%" align="center" border="1">
#{
var i = 0;
while (i < Model.CompanyMaster.Count)
{
<tr>
<td style="width:50%" hidden="hidden"><input type="checkbox" class="EntityCheck" id="chkCompanyId" /> #Model.CompanyMaster[i].COMPANYID</td>
#if ((i + 1) < Model.CompanyMaster.Count)
{
<td><input type="checkbox" class="EntityCheck" /> #Model.CompanyMaster[i + 1].COMPANY_NAME</td>
<td><input type="checkbox" class="CurrentYear" /> #DateTime.Now.Year </td>
<td><input type="checkbox" class="PreviousYear" /> #DateTime.Now.AddYears(-1).Year </td>
<td><input type="checkbox" class="LastYear" /> #DateTime.Now.AddYears(-2).Year </td>
}
else
{
<td></td>
}
</tr>
i = i + 1;
}
}
</table>
</div>
</td>
</tr>
With above code, I am able to populate data in a table with multiple checkboxes, but unable to get the value of the checkbox where the class name is something other than EntityCheck. Below is my jQuery function:
function GetSelectedEntities() {
var entities = "";
$("#divEntities").find('td').each(function (i, el) {
var checkbox = $(this).find('input.EntityCheck');
//var check1 = $(this).find('CurrentYear');
//var check2 = $(this).find('PreviousYear');
//var check3 = $(this).find('LastYear');
var check1 = $('.CurrentYear').val();
var check2 = $('.PreviousYear').val();
var check3 = $('.LastYear').val();
if (checkbox != undefined && $(checkbox).length > 0 && $(checkbox).prop('checked') == true) {
var EntityData = jQuery.trim($(this).text());
if (entities == "") {
entities = EntityData;
}
else {
entities = entities + "|" + EntityData;
}
}
});
return entities;
}
jQuery function is invoked on a button click event:
<button style="font:normal 9pt Arial;height:30px;width:100px;border-radius:5px; border:none; background-color:royalblue; color:white" id="btnAdd" onclick="GetSelectedEntities(event);">
Add
</button>
I tried by giving the same class name to all the checkboxes but the problem was that I was able to get the values of the year checkbox, even if the CompanyName was not selected. I need the year values only if the CompanyName checkbox is checked and it's corresponding years. I also tried by giving the id='' to the year checkbox, but could not get the values.
I am unable to figure where I am going wrong. What is that I need to change in my jQuery to get the expected result?
Something like this would work:
$('#btnAdd').on('click', function(){
var checked = $('table').find('input:checked');
checked.each(function(){
alert($(this).closest('td').text());
//do your stuff here..
});
});
Se working fiddle: https://jsfiddle.net/c8n4rLjy/
I had to make changes to get the desired solution. Please find the solution below:
<tr>
<td colspan="4" align="center">
<div id="divEntities" style="width:100%;height:150px;overflow-y:scroll;align:center;">
<table cellspacing="2" cellpadding="2" width="95%" align="center" border="1">
#{
var i = 0;
while (i < Model.CompanyMaster.Count)
{
<tr>
<td style="width:50%" hidden="hidden"><input type="checkbox" class="EntityCheck" id="chkCompanyId" /> #Model.CompanyMaster[i].COMPANYID</td>
#if ((i + 1) < Model.CompanyMaster.Count)
{
<td><input type="checkbox" class="EntityCheck" /> #Model.CompanyMaster[i + 1].COMPANY_NAME</td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.Year </td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.AddYears(-1).Year </td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.AddYears(-2).Year </td>
}
else
{
<td></td>
}
</tr>
i = i + 1;
}
}
</table>
</div>
</td>
</tr>
jQuery:
function GetSelectedEntities() {
var entities = "";
var CompanySelected = false;
var counter = 0;
$("#divEntities").find('td').each(function (i, el) {
counter = counter + 1
var checkbox = $(this).find('input.EntityCheck');
var checkboxyear = $(this).find('input.chkYear');
if (counter == 2) {
if (checkbox != undefined) {
if ($(checkbox).prop('checked') == true) {
CompanySelected = true;
var EntityData = jQuery.trim($(this).text());
if (entities == "") {
entities = EntityData;
}
else {
entities = entities + "-" + EntityData;
}
}
else {
CompanySelected = false;
}
}
}
if (counter > 2) {
if (CompanySelected == true) {
if (checkboxyear != undefined) {
if ($(checkboxyear).prop('checked') == true) {
var EntityData = jQuery.trim($(this).text());
entities = entities + "|" + EntityData;
}
}
}
}
if(counter == 5)
{
counter = 0;
}
});
return entities;
}

jquery select custom attribute in child controls

I have a table with class="cloneable" that has rows containing one control per row. The controls may be textarea, checkbox, radio, or input[type=number]. Each control has a custom data-answersetid attribute. I would like to select all child controls under the .cloneable class and update each of the data-answersetid attributes to the value of a counter variable, lastanswersetid. I tried the following but it didn't work.
let lastanswersetid: number = 0;
const me: any = $('.cloneable').last(); //there might be several cloneables so just get the last cloneable
$('*[answersetid]', me) ? .each(function(index, value) {
console.log(index, value);
console.log($(this));
lastanswersetid++;
$(this).prop('aswersetid', lastAnswersetid);
}); //set the data-answersetid to the last answerset value
<table id="questionTable" class="table #("Q33,Q65".Contains(Model.QuestionnaireAndChoices.First().QuestionKey) ? "cloneable" : "")">
<tbody>
#foreach (var item in Model.QuestionnaireAndChoices)
{
<tr id="#item.QuestionID"
#("Q64".Contains(item.QuestionKey) ? "class=cloneable" : "Q70,Q71".Contains(item.QuestionKey) ? "class=notCloneable" : "")>
<td>
#Html.DisplayFor(modelItem => item.QuestionKey)
</td>
<td class="question">
#Html.DisplayFor(modelItem => item.Question)
</td>
<td>
#switch (item.ChoiceUIType)
{
case "UI-CHK":
#await Component.InvokeAsync("Checkbox2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices });
break;
case "UI-DROP1":
#await Component.InvokeAsync("Dropdown2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices });
break;
case "UI-RAD":
#await Component.InvokeAsync("RadioButton2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices, question = item.Question, radioGroupName = item.QuestionKey });
break;
case "UI-NUMBER":
{
int thisLength = 10;
string thisUiWidth = "150px";
if (item.QuestionKey == "Q38")
{
thisLength = 3;
}
#await Component.InvokeAsync("Input", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices, inputLength = thisLength, uiWidth = thisUiWidth });
break;
}
case "UI-TXT":
{
<div class="md-form amber-textarea active-amber-textarea">
<textarea name="#item.QuestionKey" id="#item.QuestionKey" class="md-textarea form-control persistable" rows="3"
data-questionid="#item.QuestionID" data-userid="#Model.UserID"
data-questionkey="#item.QuestionKey"
data-useranswerid="#item.Choices.FirstOrDefault()?.UserAnswerID"
data-codesetid="#item.Choices.FirstOrDefault()?.ChoiceID"
data-oldvalue="#item.Choices.FirstOrDefault()?.OtherDescription"
data-answersetid="#item.Choices.FirstOrDefault()?.AnswerSetID"
data-toggle="tooltip" data-placement="left"
title="#(!string.IsNullOrEmpty(item.Choices.FirstOrDefault()?.OtherDescription) ? string.Format("Answered by {0}", item.Choices.First().AnsweredBy) : "")">#item.Choices.FirstOrDefault()?.OtherDescription</textarea>
</div>
break;
}
default:
{
#*just display the text*#
<div>Render raw text here</div>
break;
}
}
</td>
</tr>
}
</tbody>
</table>
Your selector is wrong, it should be [data-answersetid], also use .data() to set the value.
$('[data-answersetid]', me) ? .each(function(index, value) {
console.log(index, value);
console.log($(this));
lastanswersetid++;
$(this).data('answersetid', lastAnswersetid);
}); //set the data-answersetid to the last answerset value
If you need the actual attribute in the DOm updated you'd need to use .attr()
$(this).attr('data-answersetid', lastAnswersetid);

How do I increase the value of 'sessionStorage.fgattempt', every time 'fgMade()' or 'threeMade()' is triggered?

So I am creating a stat tracker for a basketball game I play and I need that every time that I make a field goal or three pointer, that the field goal attempts go up as well. Also may need a way to shorten the javascript code I have written here.
Basically what is being asked is how to go about increasing the value of 'sessionStorage.fgattempt', for every time that both the functions 'fgMade()' and 'threeMade()' are run. It would also be nice to see that 'threeMade()' increases 'sessionStorage.threeattempt' as well.
<!DOCTYPE html>
<html>
<head>
<script>
function fgMade() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.fgmade) {
sessionStorage.fgmade = Number(sessionStorage.fgmade) + 1;
} else {
sessionStorage.fgmade = 1;
}
document.getElementById("result1").innerHTML = sessionStorage.fgmade;
} else {
document.getElementById("result1").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function fgAttempt() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.fgattempt) {
sessionStorage.fgattempt = Number(sessionStorage.fgattempt) + 1;
} else {
sessionStorage.fgattempt = 1;
}
document.getElementById("result2").innerHTML = sessionStorage.fgattempt;
} else {
document.getElementById("result2").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function threeMade() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.threemade) {
sessionStorage.threemade = Number(sessionStorage.threemade) + 1;
} else {
sessionStorage.threemade = 1;
}
document.getElementById("result3").innerHTML = sessionStorage.threemade;
} else {
document.getElementById("result3").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function threeAttempt() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.threeattempt) {
sessionStorage.threeattempt = Number(sessionStorage.threeattempt) + 1;
} else {
sessionStorage.threeattempt = 1;
}
document.getElementById("result4").innerHTML = sessionStorage.threeattempt;
} else {
document.getElementById("result4").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function block() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.block) {
sessionStorage.block = Number(sessionStorage.block) + 1;
} else {
sessionStorage.block = 1;
}
document.getElementById("result5").innerHTML = sessionStorage.block;
} else {
document.getElementById("result5").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function steal() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.steal) {
sessionStorage.steal = Number(sessionStorage.steal) + 1;
} else {
sessionStorage.steal = 1;
}
document.getElementById("result6").innerHTML = sessionStorage.steal;
} else {
document.getElementById("result6").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function defRebound() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.defrebound) {
sessionStorage.defrebound = Number(sessionStorage.defrebound) + 1;
} else {
sessionStorage.defrebound = 1;
}
document.getElementById("result7").innerHTML = sessionStorage.defrebound;
} else {
document.getElementById("result7").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function offRebound() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.offrebound) {
sessionStorage.offrebound = Number(sessionStorage.offrebound) + 1;
} else {
sessionStorage.offrebound = 1;
}
document.getElementById("result8").innerHTML = sessionStorage.offrebound;
} else {
document.getElementById("result8").innerHTML = "Sorry, your browser does not support web storage...";
}
}
function turnover() {
if (typeof(Storage) !== "undefined") {
if (sessionStorage.tocount) {
sessionStorage.tocount = Number(sessionStorage.tocount) + 1;
} else {
sessionStorage.tocount = 1;
}
document.getElementById("result9").innerHTML = sessionStorage.tocount;
} else {
document.getElementById("result9").innerHTML = "Sorry, your browser does not support web storage...";
}
}
</script>
<style>
table,
th,
td {
border: 1px solid black;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>FGM</th>
<th>FGA</th>
<th>3PM</th>
<th>3PA</th>
<th>BLK</th>
<th>STL</th>
<th>DREB</th>
<th>OREB</th>
<th>TO</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div id="result1">N/A</div>
</td>
<td>
<div id="result2">N/A</div>
</td>
<td>
<div id="result3">N/A</div>
</td>
<td>
<div id="result4">N/A</div>
</td>
<td>
<div id="result5">N/A</div>
</td>
<td>
<div id="result6">N/A</div>
</td>
<td>
<div id="result7">N/A</div>
</td>
<td>
<div id="result8">N/A</div>
</td>
<td>
<div id="result9">N/A</div>
</td>
</tr>
</tbody>
</table>
<p><button onclick="fgMade()" type="button">FGM</button></p>
<p><button onclick="fgAttempt()" type="button">FGA</button></p>
<p><button onclick="threeMade()" type="button">3PM</button></p>
<p><button onclick="threeAttempt()" type="button">3PA</button></p>
<p><button onclick="block()" type="button">BLK</button></p>
<p><button onclick="steal()" type="button">STL</button></p>
<p><button onclick="defRebound()" type="button">DREB</button></p>
<p><button onclick="offRebound()" type="button">OREB</button></p>
<p><button onclick="turnover()" type="button">TO</button></p>
</body>
</html>
I'm assuming that this is the kind of thing you're looking for? FYI. This solution will still operate without having access to session storage, which in my opinion is nearly an essential part to include.
// A simple way to encapsulate the code into some object,
// yet due to being a self invoked function, it still has the
// luxury of 'private' properties.
const App = function(myNameSpace) {
let state = { // Initial app state.
fgmade: 0,
fgattempt: 0,
threemade: 0,
threeattempt: 0,
block: 0,
steal: 0,
defrebound: 0,
offRebound: 0,
turnover: 0
};
// A simple method to load the state from session storage.
const loadState = () => {
try {
if (sessionStorage.getItem("appState") != null) {
state = JSON.parse(sessionStorage.getItem("appState"));
}
} catch (e) {
// todo?
}
};
// A simple state method to update the applciation state in session storage.
const setState = () => {
try {
sessionStorage.setItem("appState", JSON.stringify(state));
} catch (e) {
// todo?
}
};
// A simple function to reste the state.
const resetState = () => {
Object.keys(state).forEach(k => state[k] = 0);
setState();
render();
};
// A VERY simple render method.
const render = () => {
document.getElementById("result1").innerHTML = state.fgmade;
document.getElementById("result2").innerHTML = state.fgattempt;
document.getElementById("result3").innerHTML = state.threemade;
document.getElementById("result4").innerHTML = state.threeattempt;
document.getElementById("result5").innerHTML = state.block;
document.getElementById("result6").innerHTML = state.steal;
document.getElementById("result7").innerHTML = state.defrebound;
document.getElementById("result8").innerHTML = state.offRebound;
document.getElementById("result9").innerHTML = state.turnover;
};
// This is the 'bulk' of the code, where it works out which property to update.
const buttonClickHandler = (e) => {
const txt = e.target.textContent.replace(/\ /g, '').toUpperCase();
switch (txt) {
case 'FGM':
updateProperty('fgmade');
updateProperty('fgattempt');
break;
case 'FGA':
updateProperty('fgattempt');
break;
case '3PM':
updateProperty('threemade');
updateProperty('fgattempt');
updateProperty('threeattempt');
break;
case '3PA':
updateProperty('threeattempt');
break;
case 'BLK':
updateProperty('block');
break;
case 'STL':
updateProperty('steal');
break;
case 'DREB':
updateProperty('defrebound');
break;
case 'OREB':
updateProperty('offRebound');
break;
case 'TO':
updateProperty('turnover');
break;
default:
resetState();
}
};
// A simple function to update some data.
const updateProperty = (key) => {
state[key] += 1;
setState();
render();
};
// A function responsible for binding events to updates & whatnot.
const dispatchEvents = () => {
document.querySelectorAll('button').forEach((button, index) => {
button.setAttribute('data-index', index);
button.addEventListener('click', buttonClickHandler);
});
};
// Public method to state the app.
myNameSpace.launch = () => {
loadState();
render();
dispatchEvents();
};
// Make sure to return the public object.
return myNameSpace;
}({});
// Very lazy solution to document.ready.
setTimeout(App.launch, 250);
table,
th,
td {
border: 1px solid black;
}
button#reset {
background: red;
border-color: red;
color: white;
}
<table>
<thead>
<tr>
<th>FGM</th>
<th>FGA</th>
<th>3PM</th>
<th>3PA</th>
<th>BLK</th>
<th>STL</th>
<th>DREB</th>
<th>OREB</th>
<th>TO</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div id="result1">N/A</div>
</td>
<td>
<div id="result2">N/A</div>
</td>
<td>
<div id="result3">N/A</div>
</td>
<td>
<div id="result4">N/A</div>
</td>
<td>
<div id="result5">N/A</div>
</td>
<td>
<div id="result6">N/A</div>
</td>
<td>
<div id="result7">N/A</div>
</td>
<td>
<div id="result8">N/A</div>
</td>
<td>
<div id="result9">N/A</div>
</td>
</tr>
</tbody>
</table>
<p><button>FGM</button></p>
<p><button>FGA</button></p>
<p><button>3PM</button></p>
<p><button>3PA</button></p>
<p><button>BLK</button></p>
<p><button>STL</button></p>
<p><button>DREB</button></p>
<p><button>OREB</button></p>
<p><button>TO</button></p>
<p><button id="reset">RESET</button></p>
My two cents..
var
basketball_scores_head = document.querySelector('#basketball-scores thead tr'),
basketball_scores_body = document.querySelector('#basketball-scores tbody tr'),
All_ScoreButton = document.querySelectorAll('#basketball-scores button'),
Scores_Vals = {},
asStorage = (typeof(Storage) !== "undefined");
;
All_ScoreButton.forEach(bt_elm=>{
let
e_TH = document.createElement('th'),
e_TD = document.createElement('td'),
ref = bt_elm.dataset.count.split(' ')[0]
;
e_TH.textContent = ref;
e_TD.textContent = "N/A";
e_TD.id = "count_"+ref;
basketball_scores_head.appendChild(e_TH);
basketball_scores_body.appendChild(e_TD);
Scores_Vals[ref] = 0;
bt_elm.onclick = IncreaseScore;
});
if (asStorage) {
if ( sessionStorage.getItem('basketball_scores') )
{
Scores_Vals = JSON.parse( sessionStorage.getItem('basketball_scores'));
for (let cnt in Scores_Vals ) {
document.getElementById("count_"+cnt).textContent = Scores_Vals[cnt].toString();
};
} else {
sessionStorage.setItem('basketball_scores', JSON.stringify(Scores_Vals) );
}
}
function IncreaseScore(e) {
e.target.dataset.count.split(' ').forEach (cnt =>{
Scores_Vals[cnt]++;
document.getElementById("count_"+cnt).textContent = Scores_Vals[cnt].toString();
});
if (asStorage) {
sessionStorage.setItem('basketball_scores', JSON.stringify(Scores_Vals) );
}
}
table#basketball-scores,
table#basketball-scores th,
table#basketball-scores td {
border : 1px solid grey;
}
table#basketball-scores th,
table#basketball-scores td {
width : 100px;
}
table#basketball-scores button {
font-weight: bold;
margin-top: 10px;
}
<table id="basketball-scores">
<thead>
<tr></tr>
</thead>
<tbody>
<tr></tr>
</tbody>
<tfoot>
<tr>
<td><button data-count="FGM FGA">+</button></td>
<td><button data-count="FGA">+</button></td>
<td><button data-count="3PM FGA">+</button></td>
<td><button data-count="3PA">+</button></td>
<td><button data-count="BLK">+</button></td>
<td><button data-count="STL">+</button></td>
<td><button data-count="DREB">+</button></td>
<td><button data-count="OREB">+</button></td>
<td><button data-count="TO">+</button></td>
</tr>
</tfoot>
</table>

Flux React gulp

Trying to create a Flux store. When I run gulp and check my index.html I get an error "Uncaught TypeError: listener must be a function"
var AppDispatcher = require('../dispatchers/app-dispatcher');
var AppConstants = require('../constants/app-constants');
var assign = require('object-assign');
var EventEmitterProto = require('events').EventEmitter.prototype;
var CHANGE_EVENT = 'CHANGE'; //broadcast this everytime there is a change
var _catalog = [];
var _cartItems = [];
var AppStore = assign(EventEmitterProto, {
emitChange: function(){
this.emit(CHANGE_EVENT)
},
addChangeListener: function(callback){
this.on(CHANGE_EVENT, callback); //<---if I comment this out code runs perfect
},
removeChangeListener: function(callback){
this.removeListener(CHANGE_EVENT, callback)
},
getCart: function(){
return _cartItems
},
getCatalog: function(){
return _catalog
},
getCartTotals: function(){
return _cartTotals()
}
});
module.exports = AppStore;
Below is the only component with a listener
var React = require('react');
var AppStore = require('../stores/app-store.js');
var RemoveFromCart = require('./app-removefromcart.js'); //this is a component
var Increase = require('./app-increaseitem'); //this is a component
var Decrease = require('./app-decreaseitem'); //this is a component
function cartItems(){
return {items: AppStore.getCart()}
}
var Catalog = React.createClass({
getInitialState:function(){
return cartItems();
},
componentWillMount: function(){
AppStore.addChangeListener(this.onChange)
},
_onChange: function(){
this.setState(cartItems());
},
render: function(){
var total = 0;
var items = this.state.items.map(function(item, i){
var subtotal = item.cost * item.qty;
total += subtotal;
return (
<tr key={i}>
<td><RemoveFromCart /></td>
<td>{item.title}</td>
<td>{item.qty}</td>
<td>
<Increase index={i} />
<Decrease index={i} />
</td>
<td>${subtotal}</td>
</tr>
);
})//end map
return (
<table className="table table-hover">
<thead>
<tr>
<th></th>
<th>Item</th>
<th>Qty</th>
<th></th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
{items}
</tbody>
<tfoot>
<tr>
<td colSpan="4" className="text-right">Total</td>
</tr>
</tfoot>
</table>
);
}
});
module.exports = Catalog;
Please help. This is really hurting my head
you might need to change
AppStore.addChangeListener(this._onChange)
logic to componentDidMount function like
componentDidMount:function(){
AppStore.addChangeListener(this._onChange)
}

AngularJS with AngularUI Bootsrap pagination directive doesn't hide results

I'm trying to use Angular-ui pagination directive for the first time and am confused why it isn't working. I can see the pagination buttons and it properly displays two pages to paginate through since there are 8 results and items-per-page="5" But all my data items are showing and not being hidden to five per page.
controller
dataService.get(uri).then(function (data) {
$scope.testimonials = data;
$scope.totalItems = $scope.testimonials.length;
$scope.currentPage = 1;
$scope.setPage = function(pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
console.log('Page changed to: ' + $scope.currentPage);
}
});
view
<table class="table table-striped" ng-show="testimonials.length">
<thead>
<th>Name</th>
<th>Message</th>
</thead>
<tbody>
<tr ng-repeat="testimonial in testimonials">
<td>{{testimonial.name}}</td>
<td>{{testimonial.message}}</td>
<td>Edit</td>
<td><button class="btn btn-danger" ng-click="delete(testimonial)">Delete</button></td>
</tr>
</tbody>
<pagination total-items="totalItems" ng-model="currentPage" items-per-page="5" ng-change="pageChanged()"></pagination>
</table>
I appreciate any advice, thanks!
Yo need filter data in your ng-reapeter code below should works
<table class="table table-striped" ng-show="testimonials.length">
<thead>
<th>Name</th>
<th>Message</th>
</thead>
<tbody>
<tr ng-repeat="testimonial in testimonials | startFrom: (currentPage-1)*5| limitTo: 5">
<td>{{testimonial.name}}</td>
<td>{{testimonial.message}}</td>
<td>Edit</td>
<td><button class="btn btn-danger" ng-click="delete(testimonial)">Delete</button></td>
</tr>
</tbody>
<pagination total-items="totalItems" ng-model="currentPage" items-per-page="5" ng-change="pageChanged()"></pagination>
</table>
filter starts from:
app.filter('startFrom', function () {
return function (input, start) {
if (input === undefined || input === null || input.length === 0
|| start === undefined || start === null || start.length === 0 || start === NaN) return [];
start = +start; //parse to int
try {
var result = input.slice(start);
return result;
} catch (e) {
// alert(input);
}
}
});
I can't find the original example I used, but this is what I have in my app.
The filter part isn't important, but the filterProducts object is what gets sliced and shown in your view. Check out the $watch for how it works.
app.controller('ProductController', function($scope, $filter, $routeParams, $rootScope, $location, Products){
$scope.Products = Products;
Products.brandLimit = $routeParams.brandLimit;
Products.brand = $routeParams.brand;
// try to avoid reloading the prod data
if (!Products.products){
Products.getProducts().then(function(data){
Products.products = data.products;
Products.pagination();
});
}else{
Products.pagination();
}
// watch for when the pagination changes
$scope.$watch('Products.currentPage + Products.numPerPage', function() {
var begin = ((Products.currentPage - 1) * Products.numPerPage);
var end = begin + Products.numPerPage;
Products.pagedProducts = Products.filteredProducts.slice(begin, end);
});
});
And in the service:
app.factory('Products', function($http, $filter, $location, $routeParams){
var Products = {
search: '',
searching: false,
filteredProducts: '',
pagedProducts: '',
getProduct: function(id){
delete Products.detail;
$http.get('/product/' + id).then(function(response){
Products.detail = response.data.product;
});
},
getProducts: function(){
return $http.get('/product').then(function(response){
return response.data;
});
},
pagination: function(){
// relies on fulltext filter
this.filteredProducts = $filter('fulltext')(this.products, this.brandLimit);
// set up default values to feed to ui pagination
this.currentPage = 1;
this.numPerPage = 10;
this.maxSize = 10;
// check the length of filtered items based on search or brand clicked (in the URL)
this.totalItems = this.filteredProducts.length;
this.numPages = Math.ceil(this.totalItems / this.numPerPage);
},
brandTitle: function() {
if (this.searching === false || this.brand) {
this.search = '';
return $routeParams.brand + " Products";
} else {
return 'Searching "' + $routeParams.brandLimit + '"';
}
},
searchTerm: function(){
if(this.search){
$location.path("search/" + this.search);
this.searching = true;
}else{
$location.path("/");
this.searching = false;
}
}
};
return Products;
});
And HTML:
<pagination ng-show="Products.numPages" total-items="Products.totalItems" ng-model="Products.currentPage" max-size="Products.maxSize" class="pagination-small" boundary-links="true" rotate="false" num-pages="Products.numPages"></pagination>
<table class="table table-striped">
<tr>
<th>Maker</th>
<th>Title</th>
<th ng-bind="product.priceDealer">Dealer Price</th>
<th>MSRP</th>
</tr>
<tr ng-repeat="product in Products.pagedProducts">
<td>{{product.brand}}</td>
<td>{{product.title}}</td>
<td ng-bind="product.priceDealer | currency"></td>
<td>{{product.msrp | currency:"$"}}<td>
</tr>
</table>
No Need of all that, use attribute of angular UI Bootstrap:
HTML
<pager total-items="totalItems" ng-model="currentPage" items-per-page="itemsPerPage"></pager>
====
and add below code in your controller
===========
$scope.totalItems = $scope.testimonials.length;
$scope.itemsPerPage = 5;
$scope.currentPage = 1;
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredtestimonials= $scope.alerts.slice(begin, end);
});
===========
Note that you need to mention ng-repeat="testimonial in filteredtestimonials"
and attribute should be in same scope of where you have used you used ng-repeat
Please let me know if you still face any issue and you can see more examples of this on: http://angular-ui.github.io/bootstrap/#/pagination
Do include :
in your page or layout page and items-per-page will not take direct value, it seems

Categories

Resources