I'm creating an array in a service and fetch some data from a db and iterative over the data to add the group id as a key in the array
angular.module('tasksApp').
factory("data", ["$http", function ($http) {
var data = {};
data.allTasks = {};
data.today = [];
data.actioned = [];
data.complete = [];
data.todaysNextNumber = 0;
data.groups = [];
data.groupNames = [];
data.nextGroupPosition = [];
data.loadTasks = function () {
return $http({
method: 'GET',
url: '/loadTasks'})
.then(function(response) {
data.allTasks = response.data;
// Get groups & create the arrays
getGroups().then(function(result) {
var allGroups = result;
for (var key in allGroups) {
var group = allGroups[key];
data.groups[group.group_id] = [];
data.groupNames[group.group_id] = group.group_name;
data.nextGroupPosition[group.group_id] = 0;
}
The id's of the data start with 1 and go up to 9.
Then, in the component I load the data to the scope:
angular.module('tasksApp').
component('tasks', {
templateUrl: 'tasks/template.tasks.html',
controller: function startUp($scope, $rootScope, data) {
// Get tasks
data.loadTasks().then(function(response) {
$scope.groups = data.groups;
$scope.today = data.today;
$scope.actioned = data.actioned;
$scope.groupNames = data.groupNames;
console.log($scope.groups);
})
}
});
and use ng-repeat to go over the data in the template:
<!-- Start of Groups -->
<div ng-repeat="(key, group) in groups" class="col-md-3">
<div class="groupBox">
<div ng-attr-id="{{'groupCell-' + key}}" ng-click="showTitleInput(key)">
<h1 ng-attr-id="{{'groupTitle-' + key}}">{{groupNames[key]}} - {{key}}</h1>
<input class="groupTitleInput" ng-attr-id="{{'groupInput-' + key}}" ng-value="groupNames[key]"></input></div>
<div ng-attr-id="{{'div' + key}}">
<div ng-repeat="task in group | orderBy:'position'" ng-attr-id="{{'task-' + task.id}}" class="taskContainer">
<div ng-attr-id="{{'taskText-' + task.id}}" class="taskText" ng-click="displayActionBar = !displayActionBar">{{task.task}}</div>
<div ng-attr-id="{{'actionBar-' + task.id}}" class="actionBar" ng-show="displayActionBar">
<div class="actionButton glyphicon glyphicon-globe todaysTasks" ng-click="displayActionBar = !displayActionBar; addToToday(task.id, task.group_id)"></div>
<div class="actionButton glyphicon glyphicon-ok actioned" ng-click="displayActionBar = !displayActionBar; markAsActioned(task.id, task.group_id)"></div>
<div class="actionButton glyphicon glyphicon-thumbs-up complete" ng-click="displayActionBar = !displayActionBar; markAsComplete(task.id, task.group_id)"></div>
<div class="actionButton glyphicon glyphicon-trash delete" ng-click="displayActionBar = !displayActionBar; deleteTask(task.id, task.group_id)"></div>
<div class="actionButton glyphicon glyphicon-remove cancel" ng-click="displayActionBar = !displayActionBar"></div>
<div class="actionButton glyphicon glyphicon-menu-up up" ng-click="pushUp(task.id, task.group_id)"></div>
<div class="actionButton glyphicon glyphicon-menu-down down" ng-click="pushDown(task.id, task.group_id)"></div></div></div></div>
<form ng-submit="addTask(key)" ><input name={{key}} class="newTaskInput" type="text" ng-model="newTaskDescription" /><form></div></div>
All this works fine but when the data is displayed a div for an '0' element is shown. If I print the array out using console.log it doesn't show a '0' element. Also, if I change the data with the id of 1 to 0 it also iterates over a 1 element. I thought that ng-repeat iterated over the elements in the array using the assigned key, not going from 0 through to the number of elements.
Does anyone know why this is happening?
Related
I'm unable to get the radio button checked even with the text matching the radio button value.
`
<div class="well pull-left clearfix" style="margin:5px;width:90px;padding:5px;" data-bind="click: $root.select_litho_layer_definition, css: {'background-highlight': $root.current_litho_layer_definition() === $data}">
<p class="text-center tight-padding no-margin"><strong data-bind="text: layer_name"></strong></p>
<div class="btn-group" style="width:90px">
<button class="btn btn-mini dropdown-toggle" data-toggle="dropdown" style="width:90px">
<span data-bind="text: 'Rev.' + revision"></span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu small-list" data-bind="foreach: $root.litho_layer_name_definitions()[_.indexOf($root.litho_layer_names(), layer_name)]" style="width:90px">
<li><a data-bind="text: 'Rev.' + revision, click: $root.litho_layer_name_select_revision"></a></li>
</ul>
</div>
<!-- ko foreach: exposure_array_names-->
<input type="radio" name="ExposureGroup" value="$parent.layer_name+$data" data-bind="click: $root.litho_layer_name_select_exposure, checked:$root.litho_layer_exposure"/>
<span data-bind="text: $data"></span><br>
<!--/ko-->
</div>
<!-- /ko -->
`
Each of the litho_layer_name_selected_definitions has an array of exposures called exposure_array_names
Now object structure looks like this.
{
"litho_layer_definition_sk": 90000026426,
"exposure_array_names": [
"IF1_EDGE",
"Combined"
],
"layer_name": "3HG",
"revision": 0
}
In the js, I have created an observable object of litho_layer_exposure
self.litho_layer_exposure = ko.observable(true);
self.litho_layer_exposure = ko.computed(function() {
var maskset = self.maskset();
if (!maskset) return [];
var defs = maskset.litho_layer_definitions;
if (_.isEmpty(defs)) return [];
var name = self.current_litho_layer_name();
if (!name) return [];
var revision = self.current_litho_layer_revision();
if (!_.isNumber(revision)) return;
_.reduce(defs, function(memo, d) {
if (d.layer_name === name && d.revision === revision){
memo.push(_.last(d.exposure_array_names));
}
return memo;
}, []);
});
self.litho_layer_exposure.subscribe(function(exposure) {
if (!_.isEmpty(exposure)) self.current_litho_layer_exposure(_.last(exposure));
});
I tried making the below change, which didn't work either
self.litho_layer_exposure = ko.computed({
read: function () {
var maskset = self.maskset();
if (!maskset) return [];
var defs = maskset.litho_layer_definitions;
if (_.isEmpty(defs)) return [];
var name = self.current_litho_layer_name();
if (!name) return [];
var revision = self.current_litho_layer_revision();
if (!_.isNumber(revision)) return;
/*var exposure = self.current_litho_layer_exposure();
if (!exposure) return [];*/
return _.reduce(defs, function(memo, d) {
if (d.layer_name === name && d.revision === revision) memo.push(d.default_exposure_name);
return memo;
}, []);
},
write: function (value) {
//update your self.chosenAge().population value here
self.current_litho_layer_exposure(value);
self.litho_layer_exposure(value);
},
owner: self
});
self.litho_layer_exposure.subscribe(function(exposure) {
if (!_.isEmpty(exposure)) self.current_litho_layer_exposure(_.last(exposure));
});
I´m pretty sure the initial error is
value="$parent.layer_name+$data"
which should lead to all inputs have literally "$parent.layer_name+$data" as value
you probably wanted to use a databinding to fill the attribute
data-bind="attr:{value: $parent.layer_name+$data}, checked: ..."
It is not like it is slow on rendering many entries. The problem is that whenever the $scope.data got updated, it adds the new item first at the end of the element, then reduce it as it match the new $scope.data.
For example:
<div class="list" ng-repeat="entry in data">
<h3>{{entry.title}}</h3>
</div>
This script is updating the $scope.data:
$scope.load = function() {
$scope.data = getDataFromDB();
}
Lets say I have 5 entries inside $scope.data. The entries are:
[
{
id: 1,
title: 1
},
{
id: 2,
title: 2
},
......
]
When the $scope.data already has those entries then got reloaded ($scope.data = getDataFromDB(); being called), the DOM element for about 0.1s - 0.2s has 10 elements (duplicate elements), then after 0.1s - 0.2s it is reduced to 5.
So the problem is that there is delay about 0.1s - 0.2s when updating the ng-repeat DOM. This looks really bad when I implement live search. Whenever it updates from the database, the ng-repeat DOM element got added up every time for a brief millisecond.
How can I make the rendering instant?
EDITED
I will paste all my code here:
The controller:
$scope.search = function (table) {
$scope.currentPage = 1;
$scope.endOfPage = false;
$scope.viewModels = [];
$scope.loadViewModels($scope.orderBy, table);
}
$scope.loadViewModels = function (orderBy, table, cb) {
if (!$scope.endOfPage) {
let searchKey = $scope.page.searchString;
let skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
let searchClause = '';
if (searchKey && searchKey.length > 0) {
let searchArr = [];
$($scope.vmKeys).each((i, key) => {
searchArr.push(key + ` LIKE '%` + searchKey + `%'`);
});
searchClause = `WHERE ` + searchArr.join(' OR ');
}
let sc = `SELECT * FROM ` + table + ` ` + searchClause + ` ` + orderBy +
` LIMIT ` + skip + `, ` + $scope.itemsPerPage;
sqlite.query(sc, rows => {
$scope.$apply(function () {
var data = [];
let loadedCount = 0;
if (rows != null) {
$scope.currentPage += 1;
loadedCount = rows.length;
if (rows.length < $scope.itemsPerPage)
$scope.endOfPage = true
for (var i = 0; i < rows.length; i++) {
let item = rows.item(i);
let returnObject = {};
$($scope.vmKeys).each((i, key) => {
returnObject[key] = item[key];
});
data.push(returnObject);
}
$scope.viewModels = $scope.viewModels.concat(data);
}
else
$scope.endOfPage = true;
if (cb)
cb(loadedCount);
})
});
}
}
The view:
<div id="pageContent" class="root-page" ng-controller="noteController" ng-cloak>
<div class="row note-list" ng-if="showList">
<h3>Notes</h3>
<input ng-model="page.searchString" id="search"
ng-keyup="search('notes')" type="text" class="form-control"
placeholder="Search Notes" style="margin-bottom:10px">
<div class="col-12 note-list-item"
ng-repeat="data in viewModels track by data.id"
ng-click="edit(data.id)"
ontouchstart="touchStart()" ontouchend="touchEnd()"
ontouchmove="touchMove()">
<p ng-class="deleteMode ? 'note-list-title w-80' : 'note-list-title'"
ng-bind-html="data.title"></p>
<p ng-class="deleteMode ? 'note-list-date w-80' : 'note-list-date'">{{data.dateCreated | displayDate}}</p>
<div ng-if="deleteMode" class="note-list-delete ease-in" ng-click="delete($event, data.id)">
<span class="btn fa fa-trash"></span>
</div>
</div>
<div ng-if="!deleteMode" ng-click="new()" class="add-btn btn btn-primary ease-in">
<span class="fa fa-plus"></span>
</div>
</div>
<div ng-if="!showList" class="ease-in">
<div>
<div ng-click="back()" class="btn btn-primary"><span class="fa fa-arrow-left"></span></div>
<div ng-disabled="!isDataChanged" ng-click="save()" class="btn btn-primary" style="float:right">
<span class="fa fa-check"></span>
</div>
</div>
<div contenteditable="true" class="note-title"
ng-bind-html="selected.title" id="title">
</div>
<div contenteditable="true" class="note-container" ng-bind-html="selected.note" id="note"></div>
</div>
</div>
<script src="../js/pages/note.js"></script>
Calling it from:
$scope.loadViewModels($scope.orderBy, 'notes');
The sqlite query:
query: function (query, cb) {
db.transaction(function (tx) {
tx.executeSql(query, [], function (tx, res) {
return cb(res.rows, null);
});
}, function (error) {
return cb(null, error.message);
}, function () {
//console.log('query ok');
});
},
It is apache cordova framework, so it uses webview in Android emulator.
My Code Structure
<html ng-app="app" ng-controller="pageController">
<head>....</head>
<body>
....
<div id="pageContent" class="root-page" ng-controller="noteController" ng-cloak>
....
</div>
</body>
</html>
So there is controller inside controller. The parent is pageController and the child is noteController. Is a structure like this slowing the ng-repeat directives?
Btw using track by is not helping. There is still delay when rendering it. Also I can modify the entries as well, so when an entry was updated, it should be updated in the list as well.
NOTE
After thorough investigation there is something weird. Usually ng-repeat item has hash key in it. In my case ng-repeat items do not have it. Is it the cause of the problem?
One approach to improve performance is to use the track by clause in the ng-repeat expression:
<div class="list" ng-repeat="entry in data track by entry.id">
<h3>{{entry.title}}</h3>
</div>
From the Docs:
Best Practice: If you are working with objects that have a unique identifier property, you should track by this identifier instead of the object instance, e.g. item in items track by item.id. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance.
For more information, see
AngularJS ngRepeat API Reference -- Tracking and Duplicates
In your html, try this:
<div class="list" ng-repeat="entry in data">
<h3 ng-bind="entry.title"></h3>
</div>
After thorough research, I found my problem. Every time I reset / reload my $scope.viewModels I always assign it to null / empty array first. This what causes the render delay.
Example:
$scope.search = function (table) {
$scope.currentPage = 1;
$scope.endOfPage = false;
$scope.viewModels = []; <------ THIS
$scope.loadViewModels($scope.orderBy, table);
}
So instead of assigning it to null / empty array, I just replace it with the new loaded data, and the flickering is gone.
I have a view with a modal pop-up that displays "parameters" or rather data from a Dictionary being passed to the front end. With my current JS, it appears my function will only deserializing one key and value at a time. However, I need to edit the function so that It can deserialize more than one key and value, if the dictionary is passing in more than one key and value..
Below is my code. If you want to know more about the back end please let me know.
Controller is returning:
var parameters = new Dictionary<string, string>();
return Json(parameters, JsonRequestBehavior.AllowGet);
To reiterate, parameters is a Dictionary that can have either one key/value OR it could hold multiple key/value pairs.
JS:
$("button[name='paramsBtn']").click(function () {
/* Grabs ID from col selected */
var $col = $(this).closest('.row').find('.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);
}
});
});
Here is the modal:
<div class="modal fade" id="paramsModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header modal-header-primary">
<a class="btn btn-xs btn-primary pull-right" data-dismiss="modal" aria-label="Close"><span class="glyphicon glyphicon-remove"></span></a>
<h4 class="modal-title" id="modalTitleText">Job Parameters</h4>
</div>
<div class="modal-body">
<div class="list-group">
<div class="row list-group-item list-group-item-heading container divTableHeading" style="width:inherit; margin-bottom:0px;">
<div class="col-md-6 font-weight-bold"> Parameter: </div>
<div class="col-md-6 font-weight-bold"> Value: </div>
</div>
<div class="row list-group-item container" style="width:inherit;">
<div class="col-md-6 text-break" id="modalName"></div>
<div class="col-md-6 text-break" id="modalMessage"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
This line is confusing:
var myKey = key;
After the loop completes, myKey will be equal to the last index in your array, so 2 if results had length 3.
So, name will equal 2 and value will be equal to the last element in results
Maybe you're looking for something like this, since results is {string, string}:
// sample results array from server
var arr = ["val1", "val2", "val3"];
var displayString = "";
for (var key in arr) {
if (arr.hasOwnProperty(key)) {
displayString += arr[key] + ","; // note, there will be a trailing comma
}
}
console.log(displayString);
See the comments below, essentially you arent doing all of the work inside the loop thus your function appears to produce 1 variable (the last one in the dictionary)
$("button[name='paramsBtn']").click(function () {
/* Grabs ID from col selected */
var $col = $(this).closest('.row').find('.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;
}
}
//Move these variables inside the loop. you are setting them once
//they are in essence being set to the last value in the dictionary
var name = myKey;
var value = results[myKey];
$('#modalName').text(name);
$('#modalMessage').text(value);
}
});
});
I am creating a dynamic, single-paged forum site using AngularJS as the front-end and Firebase as the back-end. The page consists of a list of threads on the left-hand side and the thread content on the right-hand side. The thread content displayed is based on the thread selected from the list.
I can successfully select a thread from the list and display its contents. However, when a thread is selected from the list, all of the other threads in the list become replicas of the selected thread. By this, I mean that the attribute values for the title, comments and votes of the selected thread are assigned to the same attributes in all of the other threads simultaneously, making them all identical. The ID of each thread does not change.
Can anybody give me some insight as to what is causing this issue? I can't identify anything in my code that would cause the attribute values of each Firebase object to be reassigned.
Here is the main.html page that contains the list and thread content sections
<div ng-controller="mainPageController">
<div>
<h3>
Welcome {{user.name}}! <button class="btn-danger img-rounded" ng-click="logout()" id="LogoutBtn">Logout</button>
</h3>
</div>
<div class="col-md-6">
<h2>All Threads</h2>
<div id="searchThreads" class="input-group col-md-5 img-rounded">
<input type="text" class="col-xs-5 form-control" ng-model="searchThread" placeholder="Search threads...">
</div>
<div id="addThread" class="input-group">
<input type="text" class="col-xs-5 form-control" ng-model="newThreadTitle" placeholder="New thread title..."/>
<button ng-click="addThread()">Add thread</button>
</div>
<!-- Thread List -->
<div>
<div ng-repeat="thread in threads | filter:searchThread | orderObjectBy:'votes'">
<button class="glyphicon glyphicon-chevron-up" ng-click="upvote(thread.$id, thread.votes)"></button> |
<button class="glyphicon glyphicon-chevron-down" ng-click="downvote(thread.$id, thread.votes)"></button>
<a href ng-click="showThread(thread)">{{thread.votes}}<span style="margin-left:1em"> {{thread.title}} by {{thread.username}}</span></a>
</div>
</div>
</div>
</div>
<!-- Thread content viiew -->
<div class="col-md-6">
<div ng-controller="threadPageController">
<h1>{{currentThread.title}} by {{currentThread.username}}</h1>
<div>
<input type="text" ng-model="newComment" placeholder="Write a comment..."/>
<button ng-click="addComment()">Add Comment</button>
</div>
<div>
<div ng-repeat="comment in currentThread.comments">{{comment.username}}: {{comment.text}}
</div>
<div ng-if="!currentThread.comments.length">There are no comments on this thread</div>
</div>
</div>
</div>
The mainPageController
angular.module('richWebApp')
.controller('mainPageController', function($scope, $location, userService, threadService, fb, $firebaseAuth, $filter){
$scope.user = userService.getLoggedInUser();
$scope.newThreadTitle = '';
$scope.currentThreadId = '';
$scope.threads = threadService.getAllThreads();
$scope.threads.$loaded().then(function(){
console.log($scope.threads)
});
$scope.users = userService.getLoggedInUsers();
$scope.addThread = function(){
if(!$scope.newThreadTitle){
return false; //Don't do anything if the text box is empty
}
var newThread = {
title: $scope.newThreadTitle,
username: $scope.user.name,
comments: [],
votes: 0
};
$scope.threads.$add(newThread);
$scope.newThread = '';
$scope.newThreadTitle = ''; //Clear the text in the input box
}
$scope.showThread = function(thread) {
$scope.$emit('handleEmit', {id: thread.$id});
};
$scope.upvote = function(threadId, threadVotes) {
var newVotes = threadVotes + 1;
var ref = new Firebase(fb.url);
var threadRef = ref.child("threads");
threadRef.child(threadId).update({
votes: newVotes
});
}
$scope.downvote = function(threadId, threadVotes) {
var newVotes = threadVotes - 1;
var ref = new Firebase(fb.url);
var threadRef = ref.child("threads");
threadRef.child(threadId).update({
votes: newVotes
});
}
$scope.logout = function(){
userService.logout();
}
});
The threadPageController
angular.module('richWebApp')
.controller('threadPageController', function($scope, $location, $routeParams, threadService, fb, userService){
$scope.$on('handleBroadcast', function (event, args) {
var threadId = args.id;
var currentThread = threadService.getThread(threadId);
currentThread.$bindTo($scope, 'currentThread') //creates $scope.thread with 3 way binding
});
$scope.newComment = '';
$scope.addComment= function(){
if(!$scope.newComment){
return false; //Don't do anything if the text box is empty
}
var currentUser = userService.getLoggedInUser();
var newComment = {
text: $scope.newComment,
username: currentUser.name
};
$scope.currentThread.comments = $scope.currentThread.comments || [];
$scope.currentThread.comments.push(newComment);
$scope.newComment = ''; //Clear the input box
}
});
threadService
angular.module("richWebApp").service("threadService", function($firebaseArray, $firebaseObject, fb){
this.getAllThreads = function(){
var ref = new Firebase(fb.url + '/threads');
return $firebaseArray(ref);
};
this.getThread = function(threadId){
var ref = new Firebase(fb.url + '/threads/' + threadId);
return $firebaseObject(ref);
};
});
I have added a server side pagination with table sorter successfully. I just would like to know how can I refresh it? I would like to create a button to call a refresh function. Does anyone know if there is any method to do it? I do not want to reload the page for it.
UPDATE:
ajaxProcessing: function(data){
if (data && data.hasOwnProperty('rows')) {
var r, row, c, d = data.rows,
total = data.total_rows,
headers = data.headers,
rows = [],
len = d.length;
for ( r=0; r < len; r++ ) {
row = []; // new row array
// cells
for (c in d[r]) {
if (typeof(c) === "string") {
row.push(d[r][c]); //add each table cell data to row array
}
}
rows.push(row); // add new row array to rows array
}
var items="";
$("#tabelaTickets tr:has(td)").remove();
if (rows!==null && rows.length!== 0) {
$.each(rows,function(index,item) {
$("#tabelaTickets").append('<tr class="danger"><td align="center" style="width: 70px"><a type="button" class="btn btn-primary btn-xs" data-placement="right" title="Visualizar ticket" data-toggle="modal" class="btn btn-primary" href="visualizar.php?ticket='+item[3]+'"> #' + item[3] + '</a></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:250px">' + item[4] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:350px;">' + item[5] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:250px;">' + item[6] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:60px;">' + item[7] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:70px;">' + item[8] + '</div></td></tr>');
});
}else{
$("#tabelaTickets").append('<tr><td colspan = "6" align="center">SEM RESULTADO A SER EXIBIDO</td></tr>');
}
$("#tabelaTickets").trigger("update");
$("#tabelaTickets").trigger("appendCache");
$("#pleaseWaitDialog").modal('hide');
// in version 2.10, you can optionally return $(rows) a set of table rows within a jQuery object
return [ total];
}
},
Thanks since now,
Erik
your repsonse is JSON, it's easy with a little AJAX function.
example your HTML is look like :
<div class="wrapper">
<div class="item">
<span>item 01</span>
</div>
<div class="item">
<span>item 02</span>
</div>
<div class="item">
<span>item 03 </span>
</div>
</div>
<button class="btn refresh-btn" type="submit"></button>
your response JSON maybe look like :
response = {
{ content : item11 },
{ content : item12 },
{ content : item13 }
};
your HTML render function with AJAX will be look like :
$('.refresh-btn').on('click', function() {
var url = 'yourUrl/?param=refresh&example=true';
var $wrapper = $('.wrapper'); // a div that wrap your new HTML.
$.get(url, {}) //call AJAX GET new item.
.done(function(data) {
$wrapper.html(''); // clear old list;
var $template = $('<div/>', {class : 'item'} ); // create item's HTML.
data.arrayItemList.forEach(function(item) {
var itemTemplate = $template.clone();
itemTemplate.append($('<span/>').text(item.content));
$wrapper.append(itemTemplate); // add new item in list.
});
});
})
that's mean : you create new HTML, and fill it with your data, everything worked fine.
Some time I create a empty template some where in view and clone it.
<div class="sample-template">
<div class="item">
<span> </span>
</div>
</div>
when I need it, I call the jQuery var $template = $('.sample-template').clone(); then fill data with $template.find('span').text(item.content);