I trying to append ng-repeat into my HTML div on load.
It recognizes the ng-repeat, however the index value isn't displaying as it should
HTML
<div id="myInnerCarousel"></div>
controller:
var myCarousel = document.getElementById('myInnerCarousel');
var newItem = document.createElement("div");
newItem.setAttribute("class","item");
var newData = document.createElement("div");
newData.setAttribute("class", "col-xs-6 col-sm-6 col-md-3 col-lg-3");
newData.setAttribute("ng-repeat", "mat in " + arr);
//Create individual values seperately
var newMaterialName = document.createElement("h4");
var nameNode = document.createTextNode("{{mat.Name}}");
newMaterialName.appendChild(nameNode);
//Append everything together
newData.appendChild(newMaterialName);
newItem.appendChild(newData);
myCarousel.appendChild(newItem);
However the result is this:
https://gyazo.com/00b76c6b910d4c6701059d404783f720
It got the right idea of displaying my array, however angular isn't displaying h4 right.
EDIT: imtrying to achieve this in my html:
<div ng-controller="myController">
<div class="item">
<div class="col-xs-6 col-sm-6 col-md-3 col-lg-3" ng-repeat="mat in array1">
<h4>{{mat.Name}}</h4>
</div>
</div>
<div class="item">
<div class="col-xs-6 col-sm-6 col-md-3 col-lg-3" ng-repeat="mat in array2">
<h4>{{mat.Name}}</h4>
</div>
</div>
Lets simply state that this is not the way to do it.
A better and more angular way would be (assuming your apps name is app).
HTML
<div ng-controller="myController">
<div class="item">
<div class="col-xs-6 col-sm-6 col-md-3 col-lg-3" ng-repeat="mat in array">
<h4>{{mat.Name}}</h4>
</div>
</div>
</div>
Angular Controller
angular.module('app').controller('myController', function($scope) {
$scope.array = [{Name: 'abc'}, {Name: 'def'}]; // or whatever your data looks like.
});
Dynamically added component should be compiled using angular. you can use $compile function of angular. Below is working code.
Jsfiddle
function TodoCtrl($scope, $compile) {
$scope.arr = [{Name: "Dynamically Added cowermponent"}];
var myCarousel = document.getElementById('myInnerCarousel');
var newItem = document.createElement("div");
newItem.setAttribute("class","item");
var newData = document.createElement("div");
newData.setAttribute("class", "col-xs-6 col-sm-6 col-md-3 col-lg-3");
newData.setAttribute("ng-repeat", "mat in arr");
//Create individual values seperately
var newMaterialName = document.createElement("h4");
var nameNode = document.createTextNode("{{mat.Name}}");
newMaterialName.appendChild(nameNode);
//Append everything together
newData.appendChild(newMaterialName);
newItem.appendChild(newData);
myCarousel.appendChild(newItem);
$compile(newItem)($scope);
}
Related
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);
}
I have made a small app using AngularJS 1.4, that outputs JSON data from a remote source.
Here is the JSON data in question.
Here is my view - the link to ngInfiniteScroll comes in at the top of the container:
<body ng-app="cn" ng-controller="MainCtrl as main">
<div id="header" class="container-fluid">
<p>Camper News</p>
</div>
<div class="container">
<div infinite-scroll="feed.loadMore()" infinite-scroll-distance="3">
<div ng-repeat="newsItem in myData" class="news-row col-sm-12 col-xs-12">
<div class="col-sm-2 col-xs-12">
<div id="img-container">
<img ng-src={{newsItem.author.picture}} id="user-avatar" />
</div>
</div>
<div class="news-text col-sm-10 col-xs-12">
<a href={{newsItem.link}}><em>{{newsItem.headline}}</em></a>
</div>
<div class="col-sm-10 col-xs-12" id="link-description">
{{newsItem.metaDescription}}
</div>
<div class="col-sm-12 col-xs-12" id="bottom-text">
<div class="col-sm-4 col-xs-12" id="author">
<a href='http://www.freecodecamp.com/{{newsItem.author.username}}'>{{newsItem.author.username}}</a>
</div>
<div class="col-sm-4 col-xs-12" id="likes">
<i class="fa fa-thumbs-o-up"></i> {{newsItem.upVotes.length}}
</div>
<div class="col-sm-4 col-xs-12" id="timestamp">
<span am-time-ago={{newsItem.timePosted}} | amFromUnix></span>
</div>
</div>
</div>
</div>
</div>
</body>
I am attempting to stagger the loading and outputting of the data using ngInfiniteScroll. I'm just not sure how it would work:
app.controller('MainCtrl', function($scope, Feed) {
$scope.feed = new Feed();
});
app.factory('Feed', function($http) {
var Feed = function() {
this.items = [];
this.after = '';
};
Feed.prototype.loadMore = function() {
var url = "http://www.freecodecamp.com/news/hot";
$http.get(url).success(function(data) {
var items = data;
// Insert code to append to the view, as the user scrolls
}.bind(this));
};
return Feed;
});
Here is a link to the program on Codepen. The code that relates to ngInfiniteScroll (controller and factory) is currently commented out in favour of a working version, but this of course loads all links at once.
What do I need to insert in my factory in order to make the JSON load gradually?
From what I can tell, by looking at FreeCodeCamps' story routes, there is no way to query for specific ranges of the "hot news" stories.
It looks to just return json with a fixed 100 story limit.
function hotJSON(req, res, next) {
var query = {
order: 'timePosted DESC',
limit: 1000
};
findStory(query).subscribe(
function(stories) {
var sliceVal = stories.length >= 100 ? 100 : stories.length;
var data = stories.sort(sortByRank).slice(0, sliceVal);
res.json(data);
},
next
);
}
You can use infinite scroll for the stories it does return to display the local data you retrieve from the request in chunks as you scroll.
i got an issue that I'm trying to solve but it seems I can't find a proper solution to achieve what I'm trying to do.
I'l try to explain my problem as best as I can: I need to create some tabs heading dynamically depending on the result of an AJAX call, so I don't know in advance how many tabs there will be, I'll post my HTML markup, my controller and what is the result I have in the DOM. I hope I'll be able to explain myself clear enough.
PART OF THE HTML MARKUP
<div id="tabPlacer">
</div>
PART OF ANGULARJS CONTROLLER
$http({method: 'GET', url: 'getNews.json'}).
success(function(data, status, headers, config) {
$scope.news = data;
createBase();
var contFirst=0;
var contSecond=0;
for (i=0; i< $scope.news.news[0].allNews.length; i++){
$scope.bodynews[i] = $scope.news.news[0].allNews[i].bodyNews;
if(i%2==0)
{
$scope.bodynewsR[contFirst] = $scope.news.news[0].allNews[i].bodyNews;
contFirst++;
}
else{
$scope.bodynewsL[contSecond] = $scope.news.news[0].allNews[i].bodyNews;
contSecond++;
}
}
$scope.noOfPages =Math.floor($scope.news.news[0].allNews.length / ($scope.itemsPerCol*2));
$scope.$watch('currentPage', function() {
begin = (($scope.currentPage - 1) * $scope.itemsPerCol);
end = begin + $scope.itemsPerCol;
$scope.pagedL = {
bodynewsL: $scope.bodynewsL.slice(begin, end)
}
$scope.pagedR = {
bodynewsR: $scope.bodynewsR.slice(begin, end)
}
});
}).
error(function(data, status, headers, config) {
});
function createBase() {
for (var i = 0; i < $scope.news.news[0].posizioni.length; i++) {
// $scope.tabsName[i] = $scope.news.news[0].posizioni[i][i];
$scope.baseString += "<tab heading='" + $scope.news.news[0].posizioni[i][i] + "' ng-controller='MainController'><div class='col-xs-12 col-sm-6 col-md-6' id='colonaDx"+ $scope.news.news[0].posizioni[i][i] +"'></div><div class='col-xs-12 col-sm-6 col-md-6' id='colonaDx"+ $scope.news.news[0].posizioni[i][i] +"'></div><div id='paginaz"+ $scope.news.news[0].posizioni[i][i] +"'></div></tab>";
}
$scope.baseString += "</tabset>";
$("#tabPlacer").html($scope.baseString);
}
});
HTML CREATED IN DOM
<div id="tabPlacer">
<tabset panel-tabs="true" panel-class="panel-grape" data-heading="OTHER NEWS">
<tab heading="allNews" ng-controller="MainController">
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxallNews">
</div>
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxallNews">
</div>
<div id="paginazallNews">
</div>
</tab>
<tab heading="SecondTab" ng-controller="MainController">
<div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxSecondTab">
</div><div class="col-xs-12 col-sm-6 col-md-6" id="colonaDxSecondTab">
</div>
<div id="paginazSecondTab">
</div>
</tab>
</tabset>
</div>
So far the problem is that nothing is visualized on the page but if I manually define in the html markup the tabset structure I can see them..any ideas? Thanks very very much in advance.
As Cetia said, you don't want to "insert" html into your template in angular. Instead, your situation probably needs ng-repeat, which is one of the very basic angular directives you should learn to use.
Basically, you'll want to store the fetched data in a $scope variable, and then use that variable with ng-repeat to display things based on your data. A basic example here:
Controller:
$scope.things = [
{
name: "Thing1",
description: "I'm the first thing!"
},
{
name: "Thing2",
description: "I'm the second thing!"
}
]
HTML:
<div ng-repeat="thing in things">
<tr>
<td>{{thing.name}}:</td>
<td>{{thing.description}}</td>
</tr>
</div>
See fiddle here: http://jsfiddle.net/m8qLdhth/1/
I am trying to lazy load images with knockoutjs binding.
I was able to lazy load images without knockoutjs framework but I am not sure how can i do that with knockoutjs binding.
Here is my HTML
<div class='liveExample'>
<div class="row">
<div data-bind="foreach: items">
<div class="col-lg-4 col-md-4 col-sm-4 " style="padding: 0px">
<img data-bind=" attr: { src: $data }" class="lazy" />
</div>
</div>
</div>
</div>
Javascript:
var SimpleListModel = function(items) {
this.items = ko.observableArray(items);
bind(this); // Ensure that "this" is always this view model
};
var pictures = []; //Initialise an empty array
for (var i = 0; i = 10 ; i++) {
var image; //This is a placeholder
image = 'http://dummyimage.com/300x200/000/fff&text=' + i; //Set the src attribute (imageFiles[i] is the current filename in the loop)
pictures.push(image); //Append the new image into the pictures array
}
ko.applyBindings(new SimpleListModel(pictures));
Here is the jsfiddle
I have made it work by adding extra div tag before foreach binding and assigning afterrender event to the parent div
<div class="row">
<div data-bind='template: {afterRender: myPostProcessingLogic }'>
<div data-bind="foreach: {data: items} ">
<div class="col-lg-4 col-md-4 col-sm-4 " style="padding: 0px">
<img data-bind=" attr: { 'data-original': $data }" class="lazy" style="min-width:100px; min-height:50px;" />
</div>
</div>
</div>
</div>
Javascript
var SimpleListModel = function(items) {
this.items = ko.observableArray(items);
this.myPostProcessingLogic = function(elements) {
$("img.lazy").lazyload({
effect: "fadeIn",
effectspeed: 2000
});
}
};
var pictures = []; //Initialise an empty array
for (var i = 1; i < 100 ; i++) {
var imageUrl = 'http://dummyimage.com/300x200/000/fff&text=' + i; //Set the image url
pictures.push(imageUrl); //Append the new image into the pictures array
}
ko.applyBindings(new SimpleListModel(pictures));
Here is the jsfiddle
I have following condition in which what i want is when my child div's first class col-md-4 and beneath div class's numeric digits 4+4+4 >= 12 then wrap those in div having class row.Fidle of my problem Fiddle
<div class="row questionsRows">
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
</div>
now i want to wrap divs in a row when my count of inner div's class is 12.
like this
<div class="row questionsRows">
<div class="row">
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
</div>
<div class="row">
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
</div>
</div>
Code i have tried :
function WrapRows() {
var RowComplete = 0;
var divs;
$('.questionsRows').children('.coulmnQuestions').each(function () {
debugger;
var classes = $(this).attr("class").split(" ");
var getFirstClass = classes[0];
var value = getFirstClass.slice(7);
RowComplete = RowComplete + value;
divs = $(this).add($(this).next());
if (RowComplete >= 12)
{
divs.wrapAll('<div class="row"></div>');
RowComplete = 0;
}
});
and its not giving desired result , its not adding first row .
<div class="row questionsRows">
<div class="col-md-4 coulmnQuestions"></div>
<div class="row">
<div class="col-md-4 coulmnQuestions"></div>
<div class="col-md-4 coulmnQuestions"></div>
</div>
</div>
I got it:
var RowComplete = 0;
var divs;
$('.questionsRows').children('.coulmnQuestions').each(function () {
var classes = $(this).attr("class").split(" ");
var getFirstClass = classes[0];
var value = parseInt(getFirstClass.slice(7));
if(RowComplete==0) {
divs = $(this);
} else {
divs = divs.add($(this))
}
RowComplete = RowComplete + value;
console.log(RowComplete)
if (RowComplete >= 12)
{
console.log(divs)
divs.wrapAll('<div class="wrapper"></div>');
RowComplete = 0;
}
});
My guess is that in this line:
divs = $(this).add($(this).next());
you are catching the next tag of <div class="col-md-4 coulmnQuestions"></div>, and you should get the same tag, I mean <div class="col-md-4 coulmnQuestions"></div> tag. So I'd do:
divs = $(this).add($(this));
Anyway, if you add the code at http://jsfiddle.net it would be easier to see for us.