Angular.js using bootstrap and dynamically creating rows - html

I am trying to figure out how to dynamically create bootstrap row divs with a class of row-fluid with angular.js using the ng-repeat directive.
Here is the angular:
<div ng-repeat="task in tasks" class="row-fluid">
<div class="span6 well">{{task.name}}</div>
</div>
This does not work though. The bootstrap html I wish to generate is:
http://jsfiddle.net/YKkXA/2/
Basically I need to do mod 2 of the index inside of the ng-repeat, and if its 0, close out the </div> and create a new <div class="row-fluid">. How is this possible?

The idea is to filter your items in order to group them, and make a second ngRepeat to iterate on sub-items.
First, add that filter to your module :
module.filter('groupBy', function() {
return function(items, groupedBy) {
if (items) {
var finalItems = [],
thisGroup;
for (var i = 0; i < items.length; i++) {
if (!thisGroup) {
thisGroup = [];
}
thisGroup.push(items[i]);
if (((i+1) % groupedBy) === 0) {
finalItems.push(thisGroup);
thisGroup = null;
}
}
if (thisGroup) {
finalItems.push(thisGroup);
}
return finalItems;
}
};
});
In your controler (because if you filter directly in your template, then you will have a $digest loop):
function TaskCtrl() {
$scope.tasksGroupBy2 = $filter('groupBy')(taskGroup, 2);
}
And in your .html :
<div ng-repeat="taskGroup in tasksGroupBy2" class="row-fluid">
<div ng-repeat="task in taskGroup" class="span6 well">{{task.name}}</div>
</div>

As an improvement to the answer Anthony gave, I would say that you could save yourself a lot of trouble using the slice method instead of going through all those conditions.
Try defining your filter as it follows:
module.filter('group', function() {
return function(items, groupItems) {
if (items) {
var newArray = [];
for (var i = 0; i < items.length; i+=groupItems) {
if (i + groupItems > items.length) {
newArray.push(items.slice(i));
} else {
newArray.push(items.slice(i, i + groupItems));
}
}
return newArray;
}
};
});
After that you can call the filter on your controller as Anthony pointed out in his response:
function Controller ($scope) {
$scope.itemsGrouped = $filter('group')(itemsArray, 5);
}

Off Topic: using bootstrap you can just place divs of class="span6 well" into one bigass row as they will stack nicely. (You will get an responsive layout too). Sorry if it was just an example of the behaviour that bootstrap can't handle. Anthony and Remigio are right; you have to create an extra module vehicle that will generate divs immersed into your ng-repeated tags.

Related

Alternative way to show details of a Wijmo flexgrid besides autoSizeRows()?

I'm looking for a way to calculate the FlexGrid height of a child grid and use that height to resize the parent grid while displaying the contents of said child grid? I'm trying to avoid using autoSizeRows() to display all the cell contents of a grid. Here, I have a slightly modified way of opening a FlexGrid asynchronously:
function autoSizeRowsAsync(grid: wjcGrid.FlexGrid) {
try {
var vr = grid.viewRange;
var gridHeight = vr.getRenderSize(grid.cells).height; //apply to parent element
for (let r = vr.topRow; r <= vr.bottomRow; r++) {
try {
var _mergedrange = grid.getMergedRange(grid.cells, r, 0);
if (_mergedrange != null) {
grid.rows[r].height = grid.rows[r].renderHeight;
//NOTE: this is the code I aim to replace with something faster
grid.autoSizeRows(_mergedrange.topRow, _mergedrange.bottomRow);
grid.refreshRange(_mergedrange);
}
else {
grid.rows[r].height = grid.rows[r].renderHeight;
}
} catch { grid.autoSizeRows(r, r); }
}
//setTimeout(() => {
// grid.autoSizeColumns();
// grid.refreshCells(true);
//}, 300);
} catch { grid.autoSizeRows(0, 0); }
}
That TypeScript function gets called in the loadedRows() grid property on the html, here:
<!--Parent grid-->
<ng-template wjFlexGridDetail
#dp="wjFlexGridDetail"
let-item="item"
[detailVisibilityMode]="'ExpandMulti'">
<wj-flex-grid #parentGrid
[itemsSource]="item.data"
(loadedRows)="loadedRows(parentGrid, gridMarkers, $event)"
(initialized)="initializeGrid(parentGrid, $event, false, false, item.label,sdp)">
<!-- Data and columns here -->
<!--Child grid-->
<ng-template wjFlexGridDetail
#sdp="wjFlexGridDetail"
let-item="item"
[detailVisibilityMode]="'ExpandMulti'"
[width]="'*'">
<wj-flex-grid #childGrid
[itemsSource]="item.otherData"
[headersVisibility]="item.anyNotFound ? 'Row' : 'None'"
(loadedRows)="loadedRows(childGrid, gridScenarios, $event)"
(initialized)="initializeGrid(childGrid, $event, true)">
</wj-flex-grid>
</ng-template>
</wj-flex-grid>
</ng-template>
loadedRows() function that calls my modified autoSizeRowsAsync() function:
public loadedRows(grid: wjcGrid.FlexGrid, parentGrid: wjcGrid.FlexGrid, eve) {
this.gridSelectionService.addGrid(grid);
if (grid.columns.visibleLength > 1) {
this.setAutoSizeColumnsDefault(grid);
} if (parentGrid != null) {
setTimeout(() => {
parentGrid.onLoadedRows();
autoSizeRowsAsync(parentGrid);
}, 50);
}
}
Is there a way to disable autoSizeRows() and manually display the grid's cell contents based on calculating the grid of the height? Would this really help make any difference in performance when displaying the grid?

How to Run a loop in jQuery to reread defined array sets?

I'm trying to build a reoccurring logic using jQuery & Arrays, but running into issues with getting the code to rerun. I'd like the code to read the next array within the matrix once the user clicks "Next Button." Currently, the logic isn't progressing past the first array, but I'm not sure why! Any help is appreciated.
<body>
<div id="wordZone"></div>
<ul id="choices">
<li></li>
<li></li>
<li></li>
</ul>
Next Word
<div class="win">
You've Won!
</div>
<div class="lose">
You've Lost!
</div>
</body>
let score = 0;
const dict = {
officeSpeak: ["Hi there!", "Regards", "Per my last email"],
counter: 0,
};
const matrix = [
["Hi there!", "Sup dude", "Salutations"],
["Regards", "Hasta luego", "Byebye"],
["Per my last email","oopsie!","some other option here, you're writing this game"],
];
const wordZone = $("#wordZone");
const choiceButtons = $("#choices li");
function buildOptions() {
let turnChoices = matrix[0];
//hide next word button - DONE
$("#next").hide();
for (let i = 0, ii = turnChoices.length; i < ii; i++) {
let choiceWord = turnChoices[i];
let choiceButton = $(choiceButtons[i]);
let btnClass = "incorrect";
choiceButton.text(choiceWord);
if (dict.officeSpeak.indexOf(choiceWord) != -1) {
btnClass = "correct";
}
choiceButton.addClass(btnClass);
}
}
buildOptions();
function onClickWord(e) {
console.log($(this));
$("#choices li").addClass("active");
$(".correct").css("color", "green");
$(".incorrect").css("color", "red");
if ($(this).hasClass("correct")) {
score++;
console.log(score);
}
$("#next").show();
let turnChoices = matrix[+1];
}
$("#choices li").click(onClickWord);
$("#next").click(buildOptions);
function finalScore() {
$("#wordZone").show(score);
if (finalScore >= 2) {
$("#wordZone").addClass("win");
$("#win").show();
} else {
$("#wordZone").addClass("lose");
$("#lose").show();
}
}
finalScore();
//final score - HELP
I tried creating a for loop where the matrix counter should increment by 1 each time the program is ran, expecting that the code would then move onto the second line of the array.
It tooks a while to find a running way. Here my suggestion:
First: create a variable with global scope
let matrixcounter = 0;
Second: Add an argument to function buildOptions and pass it to your array matrix[]:
function buildOptions(wordCounter) {
let turnChoices = matrix[wordCounter];
...
}
This last change needs another important change, based on How can I pass arguments to event handlers in jQuery? :
So replace $("#next").click(buildOptions); with
$("#next").click(function() {
matrixcounter++; //means matrixcounter = matrixcounter + 1;
buildOptions(matrixcounter);
});
A running example: https://jsfiddle.net/reporter/rtqgveuo/1/

ES6 - generators using for count

I was trying to create a counter using generators where user will click on the button and the count value will be increased. When i tried to get the function i am not getting that one. Am i missing something .
Thanks in Advance
index.html
<div class="counter">
<div id="count-gen">0</div>
<button onclick="countGen()">Count</button>
</div>
index.js
function* countGen(){
let count =0;
let nextValue = yield count++
document.getElementById('count-gen').innerHTML = nextValue
}
You've conflated two things which should be separate: Your generator, and the event handler for using your generator. You also need to be using the generator's iterator:
The generator (note the loop):
function* countGen() {
let count = 0;
while (true) {
yield ++count;
}
}
(I also made it a pre-increment as you appeared to want to start at 1.)
Getting the iterator:
const count = countGen();
Using the iterator:
function handler() {
document.getElementById('count-gen').innerHTML = count.next().value;
}
Live Example:
function* countGen() {
let count = 0;
while (true) {
yield ++count;
}
}
const count = countGen();
function handler() {
document.getElementById('count-gen').innerHTML = count.next().value;
}
document.querySelector("button").addEventListener("click", handler);
<div class="counter">
<div id="count-gen">0</div>
<button>Count</button>
</div>
(The example also uses addEventListener rathern than an onxyz-attribute handler.)

Create div with AngularJS

I know it is very simple but I wanna ask how to create div in ng-Repeat including an object proprty defines count of object.
For example i have an object like
function rowModel() {
this.id = 0;
this.columnCount = 1;
}
And I filled an array like below
$scope.Rows = [];
$scope.AddRow = function() {
var newRow = new rowModel();
newRow.id = 1;
newRow.columnCount = 3;
$scope.Rows.push(newRow);
}
I just wanna create an html template including 3 divs in each row.
This is my html and I wanna duplicate .cell div 3 times which is defined in object model
<button class="button" ng-click="AddRow()">Satır Ekle</button>
<div class="row cells{{row.columnCount}} bg-cyan" ng-repeat="row in Rows">
<div class="cell" ng-repeat="column in row.columnCount">{{row.id}}</div>
</div>
Anyone help?
Thanks
Use the following code in your controller
$scope.getNumber = function(num) {
return new Array(num);
}
And use the following in your view
<button class="button" ng-click="AddRow()">Satır Ekle</button>
<div class="row cells{{row.columnCount}} bg-cyan" ng-repeat="row in Rows">
<div class="cell" ng-repeat="column in getNumber(row.columnCount) track by $index">{{row.id}}</div>
</div>
Also if you do not want touch controller you can do this
ng-repeat="_ in ((_ = []) && (_.length=row.columnCount) && _) track by $index"
Here is the post where I found it.
i would create a filter for this
angular.module('myApp')
.filter('range', function(){
return function(n) {
var res = [];
for (var i = 0; i < n; i++) {
res.push(i);
}
return res;
};
});
After that, on the view is possible to use like this:
<div class="cell" ng-repeat="column in row.columnCount | range">{{row.id}}</div>

Knockout cross class data binding

Goal: Give the user the ability to adjust mapping results.
I am running into an issue where I need to actually change the instance used of a data bound element. Disclaimer: My json data structure may be off and I am open to possible modifications. I am coding a table header mapping app so a user can verify that the headings mapped by the server are correct. The user will have the ability to map the headers if there is an issue. I have not been able to figure out how to actually update the data bound to the result when the select menu is changed. It feels like it should be super easy. I keep finding myself with basically a finished knockout app less the last step...
Markup Snippet:
<div id="wrapper" data-bind="foreach: headings">
<h1>Bind from this</h1>
<select data-bind="value: selectMenuIdVal, event: { change: updateListing }">
<option> </option>
<!-- ko foreach: $root.headings -->
<option data-bind="value: $data.CC_FIELD_ID, visible: $data.VENDOR_FIELD_NAME(), text: $data.VENDOR_FIELD_NAME"></option>
<!-- /ko -->
</select>
<h1>To this</h1>
<ul data-bind="foreach: listingFields">
<li data-bind="text: $data.VALUE"></li>
</ul>
</div>
KO Snippet:
var Heading = function(data) {
var self = this;
var heading = ko.mapping.fromJS(data, {}, this);
heading.selectMenuIdVal = ko.observable(heading.CC_FIELD_ID());
// heading.listingFields gets mapped by the mapping plugin
this.updateListing = function(ko_evt, js_evt) {
//TODO
// Get the listing results from the value of the select menu
// self.listingFields(those listings);
}
return heading;
}
Here is my fiddle: http://jsfiddle.net/breck421/SLT9B/1/
I really not sure if undertood you right.
Please let me know if this is what you are looking for :
this.updateListing = function (ko_evt, js_evt) {
console.log("fired");
//Do something freaking awesome!!!!!!!
if (vm.dataRepo) {
for (var i = 0; i < vm.dataRepo.HEADINGS.length; i++) {
if (vm.dataRepo.HEADINGS[i].CC_FIELD_ID == heading.selectMenuIdVal()) {
var listingFields = [];
for (var j = 0; j < vm.dataRepo.LISTINGS.length; j++) {
var listing = vm.dataRepo.LISTINGS[j];
var field = listing[i];
if (field) {
listingFields.push(field);
}
}
heading.listingFields(listingFields);
// heading.listingFields = listingFields;
}
}
}
}
See fiddle
I hope it helps.