Angularjs creating a div grid from a list - javascript

I am new to AngularJS and i am trying to create the following structure:
<div class="zones">
<div class="row-fluid">
<button id="btn94" class="span4 btn">All Zones</button>
<button id="btn95" class="span4 btn">Zone 1</button>
<button id="btn96" class="span4 btn">Zone 2</button>
</div>
<div class="row-fluid">
<button id="btn97" class="span4 btn">Zone 3</button>
<button id="btn98" class="span4 btn">Zone 4</button>
<button id="btn99" class="span4 btn">Zone 5</button>
</div>
<div class="row-fluid">
<button id="btn100" class="span4 btn">Zone 6</button>
</div>
</div>
In my controller I am fetching the zones via restful web service and populating a scope object, successfully.
** Controller *
ZonesFactory.query( function(data) {
// success handler
var resultType = data.resulttype;
var objects = data.result.value;
$scope.zoneList= [];
console.log(objects);
if(resultType == "list"){
angular.forEach(objects, function (item) {
$resource(item.href).get(function(rowData) {
$scope.zoneList.push(rowData.zone);
});
});
}
}, function(error) {
// error handler
});
** In HTML **
<div class="zones">
<div class="row-fluid">
<span ng-repeat="zone in zoneList">
<button id="{{$index}}" class="span4 btn">{{zone}}</button>
<span ng-if="({{$index}}%3) == 0"> </div><div class="row-fluid"> </span >
<span>
</div>
</div>
Though, i was able to break into a new div after every three items in the list.
I am faced with the following:
1. generating a simple grid structure with div and no spans
2. how to generate the ids by incrementing an ID of say btnX (where X is a number).
Please, how can i construct the grid structure using thw div and incrementing the number part of the button ID.

You can ng-repeat over an array of numbers representing your rows, and use a nested ng-repeat coupled with ng-if to display buttons with the appropriate indexes.
<div class="zones">
<div class="row-fluid" ng-repeat="row in [0,1,2]">
<button id="btn{{94+$index}}"
ng-repeat="zone in zoneList"
ng-if="($index)/3 < row + 1 && ($index)/3 >= row" class="span4 btn">
{{zone}}
</button>
</div>
</div>
The ng-if logic could be prettier, but you get the idea.
The id of each button is created with simple interpolation. I add 94 to each $index only to match the output expected in your question. You could replace 94 with a variable initialized on your scope to ensure uniqueness.
Here is a working demo: http://plnkr.co/edit/oxdD0bRq626DbzzA54c4?p=preview

I have cracked a solution that works for me, as follows:
* IN CONTROLLER **
app.filter('partition', function($cacheFactory) {
var arrayCache = $cacheFactory('partition');
var filter = function(arr, size) {
if (!arr) { return; }
var newArr = [];
for (var i=0; i<arr.length; i+=size) {
newArr.push(arr.slice(i, i+size));
}
var cachedParts;
var arrString = JSON.stringify(arr);
cachedParts = arrayCache.get(arrString+size);
if (JSON.stringify(cachedParts) === JSON.stringify(newArr)) {
return cachedParts;
}
arrayCache.put(arrString+size, newArr);
return newArr;
};
return filter;
});
* IN HTML **
<div class="zones">
<div class="row-fluid" ng-repeat="zones in zoneList | partition:3" ng-init="outerIndex = $index">
<button id="{{'btn'+(94 + outerIndex*3+ $index)}}" class="span4 btn" ng-repeat="zone in zones">{{'btn'+(94 + outerIndex*3+ $index)}} {{zone}}</button>
</div>
</div>
Thanks for the comments, especially the fiddle. Thanks.

Related

data- attribute not working to grab dynamic id from foreach

I am using JS in a razor page to grab a dynamic ID from a col in a foreach.
In the past, I have used this and it worked fine. However, it seems that it is currently only grabbing the ID from the first col no matter which one I click.
Can someone please tell me if I am still doing this right? Or if I am missing something. Thank you.
View:
<div class="list-group container" id="JobRequestMonitorTable">
<div class="row list-group-item list-group-item-heading container divTableHeading" style="margin-bottom:0px;">
<div class="col-md-4"> Job Code </div>
<div class="col-md-4"> Description </div>
<div class="col-md-2"> Schedule </div>
<div class="col-md-1"> Running </div>
<div class="col-md-1"></div>
</div>
#if (!string.IsNullOrEmpty(ViewBag.ErrorMessage))
{
<div class="row list-group-item-danger">
<div class="col-md-1 text-center">#ViewBag.ErrorMessage</div>
</div>
}
#foreach (var item in Model.JobRequests)
{
<div class="row list-group-item container">
<div class="hidden" data-id="#item.JobRequestId" id="requestId">#item.JobRequestId</div>
<div class="col-md-4">#item.JobCode</div>
<div class="col-md-4">#item.Description</div>
<div class="col-md-2">#item.Schedule</div>
#if (#item.IsRunning == true)
{
<div class="col-md-1" style="margin-left:25px;"><span class="glyphicon glyphicon-ok"></span></div>
<div class="col-md-1"></div>
}
else
{
<div class="col-md-1"></div>
<div class="col-md-1">
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn"></button>
</div>
}
</div>
}
</div>
JS:
$("button").click(function () {
var col = $('#requestId');
var jobRequestId = col.data('Id');
$.ajax({
url: '#Url.Action("JobPollerParameters", "Tools")',
data: { "jobRequestId": jobRequestId},
success: function (results) {
$modal = $('#paramsModal');
$modal.modal("show");
var arr = results;
//loop through arr created from dictionary to grab key(s)
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
var myKey = key;
}
}
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
Really the only important part to see in the JS is var col = $('#requestId');
var jobRequestId = col.data('Id');
But I suppose I will include the whole script just in case people ask.
Your loop is creating multiple #requestId and #paramModalBtn elements when id attributes have to be unique within the DOM. Change the logic to use common classes instead. Then you can traverse the DOM to find the elements related to the button which was clicked. Try this:
$("button").click(function() {
var $col = $(this).closest('.row').find('.requestId');
var jobRequestId = $col.data('id');
console.log(jobRequestId);
// AJAX request...
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
<div class="row list-group-item container">
<div class="hidden requestId" data-id="foo-bar">Job #1</div>
<!-- other content... -->
<div class="col-md-1">
<button class="glyphicon glyphicon-list-alt btn btn-primary" name="paramsBtn"></button>
</div>
</div>
<div class="row list-group-item container">
<div class="hidden requestId" data-id="lorem-ipsum">#Job #2</div>
<!-- other content... -->
<div class="col-md-1">
<button class="glyphicon glyphicon-list-alt btn btn-primary" name="paramsBtn"></button>
</div>
</div>
All of your items inside the loop are getting the same id attribute, it is hard-codded
id="requestId"
the jQuery selector $('#requestId') is getting back the first one, this is by design.
I would add a data-id to each button and select the relevant col with that id.
For example the button will get:
<button data-col-id="#item.JobRequestId" class="glyphicon glyphicon-list-alt btn btn-primary"></button>
And then, its easy to grab that info on click:
$("button").click(function () {
var jobRequestId = $(this).data('col-id');
$.ajax({
url: '#Url.Action("JobPollerParameters", "Tools")',
data: { "jobRequestId": jobRequestId},
success: function (results) {
$modal = $('#paramsModal');
$modal.modal("show");
var arr = results;
//loop through arr created from dictionary to grab key(s)
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
var myKey = key;
}
}
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
I like this solution as you are not depended on your HTML structure and hierarchy thus selectors won't break often.
Once you have a button for each item, you could also store the data into the button value attribute, which leads to a simple implementation in the JS:
$("button").click(function (e) {
var jobRequestId = $(e.target).val();
console.log(jobRequestId);
$.ajax({
url: '#Url.Action("JobPollerParameters", "Tools")',
data: { "jobRequestId": jobRequestId},
success: function (results) {
$modal = $('#paramsModal');
$modal.modal("show");
var arr = results;
//loop through arr created from dictionary to grab key(s)
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
var myKey = key;
}
}
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="1">Job 1</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="2">Job 2</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="3">Job 3</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="4">Job 4</button><br />
<button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="5">Job 5</button>
Obs.: value must be equal to #item.JobRequestId like so: <button class="glyphicon glyphicon-list-alt btn btn-primary" id="paramModalBtn" name="paramsBtn" value="#item.JobRequestId">Job 5</button>

How to loop through JavaScript object in HTML?

I want to loop through a JavaScript object and repeat an html script as many times as the object length.
Here, I have the following in a script tag
<script>
var obj;
ipcRenderer.on('requests-results', (event, hosSchema) => {
obj = hosSchema
})
</script>
obj is an array retrieved from Mongo database as the picture below shows:
and I have the following inside <body> tag:
<div class="row">
<div class="col-md-4 col-sm-4">
<div class="card">
<div class="card-content">
<span class="card-title">.1.</span>
<p>.2.</p>
</div>
<div class="card-action">
.3.
.4.
</div>
</div>
</div>
</div>
How can I loop through obj to repeat the code between <div> tag as many times as obj.length?
I would suggest you to use Handlebars as #Amit mentioned.
first move out the code inside <div id="page-inner"> as below:
<div id="page-inner">
</div>
<script id= "requests-template" type="text/x-handlebars-template">
<div class="row">
{{#each requests}}
<div class="col-md-4 col-sm-4">
<div class="card">
<div class="card-content">
<span class="card-title">{{this.fieldName}}</span>
<p>{{this.fieldName}}</p>
</div>
<div class="card-action">
{{this.fieldName}}
{{this.fieldName}}
</div>
</div>
</div>
{{/each}}
</div>
</script>
Then inside another script page of type text/javascript you create the requests and assigned obj/hosSchema to it as below:
<script type="text/javascript">
var requestInfo = document.getElementById('requests-template').innerHTML;
var template = Handlebars.compile(requestInfo);
var requestData = template({
requests: obj
})
$('#page-inner').html(requestData);
</script>
NOTE: you need handlebars package installed (npm install handlebars --save)
Use templating script like Handlebars.js, Mustache.js or underscore.js.
Check below link for more description.
http://www.creativebloq.com/web-design/templating-engines-9134396
Try this:
var divlist = document.getElementsByTagName['div'];
var duplicate = null;
var rowIndex = -1;
var found = false;
for(var i = 0;i<obj.length;i++)
{
if(!found)
for(var p = 0;p<divlist.length;p++)
{
if(rowIndex != -1 && duplicate != null)
{
//set a Boolean to true and break
found = true;
break;
}
if(divlist[p].className == "col-md-4 col-sm-4")
{
//copy the element
duplicate = divlist[p];
}
else if(divlist[p].className == "row")
{
//identify the row's index
rowIndex = p;
}
}
//append the duplicate
divlist[rowIndex].appendChild(duplicate);
}

How update list in AngularJS?

I created one TODO List in AngularJS but I didn't finish the update function. I have some difficulty.
How do I create the update function?
Link: https://plnkr.co/edit/XfWoGVrEBqSl6as0JatS?p=preview
<ul class="list-todo">
<li ng-repeat="t in tasks track by $index">
<div class="row">
<div class="six columns">
<p>{{ t }}</p>
</div>
<div class="three columns">
<button class="button" ng-click="update()">update</button>
</div>
<div class="three columns">
<button class="button" ng-click="delete()">x</button>
</div>
</div>
</li>
</ul>
Angular Code:
angular.module('todoTest', [])
.controller('todoController', function($scope) {
$scope.tasks = [];
$scope.add = function() {
$scope.tasks.push($scope.dotask);
}
$scope.update = function(){
$apply.tasks.push($scope.dotask);
}
$scope.delete = function() {
$scope.tasks.splice(this.$index, 1);
}
})
If you want to update the value you have to pass as parameter the position of the task inside the tasks array ($index is the position):
<button class="button" ng-click="update($index)">update</button>
And then the update function would be:
$scope.update = function(index){
$scope.tasks[index] = $scope.dotask;
}
Is that what you needed?
Button for updating. Visible only while updating.
<div class="row">
<button type="submit" class="u-full-width button button-primary">Criar Tarefa</button>
<button ng-show="updateMode" ng-click="update()" type="button" class="u-full-width button button-primary">Update</button>
</div>
New update function.
$scope.update = function(index) {
if ($scope.updateMode) {
$scope.tasks[$scope.updateIndex] = $scope.dotask;
$scope.updateMode = false;
} else {
$scope.dotask = $scope.tasks[index];
$scope.updateMode = true;
$scope.updateIndex = index;
}
If you click update on the task it will make the big update button visible and bring the old todo to the input. After hitting the big update button the todo task will update.
Plunker

Search data on click event of button using smart table

I am very new to the smart table. I have gone through its documentation on Smart Table.
But the I haven't found how to bind data on click event in smart table?
Code is very big but I am trying to post it here.
<div class="table-scroll-x" st-table="backlinksData" st-safe-src="backlinks" st-set-filter="myStrictFilter">
<div class="crawlhealthshowcontent">
<div class="crawlhealthshowcontent-right">
<input type="text" class="crserachinput" placeholder="My URL" st-search="{{TargetUrl}}" />
<a class="bluebtn">Search</a>
</div>
<div class="clearfix"></div>
</div>
<br />
<div class="table-header clearfix">
<div class="row">
<div class="col-sm-6_5">
<div st-sort="SourceUrl" st-skip-natural="true">
Page URL
</div>
</div>
<div class="col-sm-2">
<div st-sort="SourceAnchor" st-skip-natural="true">
Anchor Text
</div>
</div>
<div class="col-sm-1">
<div st-sort="ExternalLinksCount" st-skip-natural="true">
External<br />Links
</div>
</div>
<div class="col-sm-1">
<div st-sort="InternalLinksCount" st-skip-natural="true">
Internal<br />Links
</div>
</div>
<div class="col-sm-1">
<div st-sort="IsFollow" st-skip-natural="true">
Type
</div>
</div>
</div>
</div>
<div class="table-body clearfix">
<div class="row" ng-repeat="backlink in backlinksData" ng-if="backlinks.length > 0">
<div class="col-sm-6_5">
<div class="pos-rel">
<span class="display-inline wrapWord" tool-tip="{{ backlink.SourceUrl }}"><b>Backlink source:</b> <a target="_blank" href="{{backlink.SourceUrl}}">{{ backlink.SourceUrl }}</a></span><br />
<span class="display-inline wrapWord" tool-tip="{{ backlink.SourceTitle }}"><b>Link description:</b> {{ backlink.SourceTitle }}</span> <br />
<span class="display-inline wrapWord" tool-tip="{{ backlink.TargetUrl }}"><b>My URL:</b> <a target="_blank" href="{{backlink.TargetUrl}}">{{ backlink.TargetUrl }}</a></span><br />
</div>
</div>
<div class="col-sm-2">
<div class="pos-rel">
{{ backlink.SourceAnchor }}
</div>
</div>
<div class="col-sm-1">
<div>
{{ backlink.ExternalLinksCount }}
</div>
</div>
<div class="col-sm-1">
<div>
{{ backlink.InternalLinksCount }}
</div>
</div>
<div class="col-sm-1">
<div ng-if="!backlink.IsFollow">
No Follow
</div>
</div>
</div>
<div class="row" ng-if="backlinks.length == 0">
No backlinks exists for selected location.
</div>
</div>
<div class="pos-rel" st-pagination="" st-displayed-pages="10" st-template="Home/PaginationCustom"></div>
</div>
and my js code is here.
module.controller('backlinksController', [
'$scope','$filter', 'mcatSharedDataService', 'globalVariables', 'backlinksService',
function ($scope,$filter, mcatSharedDataService, globalVariables, backlinksService) {
$scope.dataExistsValues = globalVariables.dataExistsValues;
var initialize = function () {
$scope.backlinks = undefined;
$scope.sortOrderAsc = true;
$scope.sortColumnIndex = 0;
};
initialize();
$scope.itemsByPage = 5;
var updateTableStartPage = function () {
// clear table before loading
$scope.backlinks = [];
// end clear table before loading
updateTableData();
};
var updateTableData = function () {
var property = mcatSharedDataService.PropertyDetails();
if (property == undefined || property.Primary == null || property.Primary == undefined || property.Primary.PropertyId <= 0) {
return;
}
var params = {
PropertyId: property.Primary.PropertyId
};
var backLinksDataPromise = backlinksService.getBackLinksData($scope, params);
$scope.Loading = backLinksDataPromise;
};
mcatSharedDataService.subscribeCustomerLocationsChanged($scope, updateTableStartPage);
}
]);
module.filter('myStrictFilter', function ($filter) {
return function (input, predicate) {
return $filter('filter')(input, predicate, true);
}
});
But It is working fine with the direct search on textbox.
but according to the requirement I have to perform it on button click.
Your suggestions and help would be appreciated.
Thanks in advance.
You can search for a specific row by making some simple tweaks.
add a filter to the ng-repeat, and filter it by a model that you will insert on the button click, like so: <tr ng-repeat="row in rowCollection | filter: searchQuery">
in your view, add that model (using ng-model) to an input tag and define it in your controller
then pass the value to the filter when you click the search button
here's a plunk that demonstrates this
you can use filter:searchQuery:true for strict search
EDIT:
OK, so OP's big problem was that the filtered values wouldn't show properly when paginated, the filter query is taken from an input box rather then using the de-facto st-search plug-in, So I referred to an already existing issue in github (similar), I've pulled out this plunk and modified it slightly to fit the questioned use case.

Change index (order) of elements via plain JS

Today I have a question: How to change index of elements via plain JS?
I have this example code:
<div class="foo">
<div class="f6x1"></div>
<div class="f6x2"></div>
<div class="f6x3"></div>
</div>
So I want to change order of (for example) first element, like this:
<div class="foo">
<div class="f6x2"></div>
<div class="f6x1"></div>
<div class="f6x3"></div>
</div>
Is there any "non-laging" example how to do that?
You need to select element and the move it before the next element after the second:
var first = document.querySelector('.f6x1'),
next = first.nextElementSibling;
first.parentNode.insertBefore(first, next.nextElementSibling);
<div class="foo">
<div class="f6x1">1</div>
<div class="f6x2">2</div>
<div class="f6x3">3</div>
</div>
Reference:
Element.querySelector
Node.nextElementSibling
Node.insertBefore
A more generic way to order the elements in any order you need:
first, start indexing using data-*-attributes:
<div class="foo">
<div data-index="1" class="f6x1"></div>
<div data-index="2" class="f6x2"></div>
<div data-index="3" class="f6x3"></div>
</div>
Second, use a function to reorder, something like:
var sortElement = document.querySelector('[data-sortable]');
document.querySelector('#buttonblock').addEventListener('click', doSort);
function doSort(e) {
var origin = e.target || e.srcElement;
if (/button/i.test(origin.nodeName)) {
var sortorder = origin.getAttribute('data-order').split(',');
orderElements(sortElement, sortorder);
}
return true;
}
function orderElements(elementRoot, order) {
var placeholder = document.createElement('div');
while(order.length) {
var current = order.shift();
var element = elementRoot.querySelector('[data-index="'+current+'"]');
if (element) {
placeholder.appendChild(element);
}
}
elementRoot.innerHTML = '';
elementRoot.innerHTML = placeholder.innerHTML;
}
<div data-sortable="true" class="foo">
<div data-index="1" class="f6x1">f6x1</div>
<div data-index="2" class="f6x2">f6x2</div>
<div data-index="3" class="f6x3">f6x3</div>
</div>
<div id="buttonblock">
<button data-order="2,1,3">sort 2, 1, 3</button>
<button data-order="3,2,1">sort 3, 2, 1</button>
<button data-order="3,1,2">sort 3, 1, 2</button>
</div>

Categories