Arrays concatenation in AngularJS and owl-carousel environment - javascript

I'm trying to load an carousel with angularjs using owl-carousel. I want my carousel to scroll endless, loading items every time the list is fully scrolled and adding queried elements to the actual list. My issue is:
When I get data from the controller of the next page, I want to merge and contact the received items to be merged the the current array and be rendered at the end of the carousel, here is what I've done:
<data-owl-carousel class="owl-carousel" data-options="{navigation: true, pagination: false, rewindNav : false}">
<div owl-carousel-item="" ng-repeat="item in hmc.ProductData.Products track by $index" class="item">
<a ng-href="/#!//{{Page.Culture+'/product/'+item.id}}">
<div class="telewebion-show-box one-row">
<div class="telewebion-show-box-cover">
<ul>
<li>{{::item.title}}</li>
<li>{{::item.price}}</li>
</ul>
</div>
<img ng-src="{{::item.picture_path}}" width="220" height="148" alt="" class="img-responsive"/>
</div>
</a>
</div>
</data-owl-carousel>
And here is my controller:
hmc.getProducts=function(){
ProductFactory.getProducts(hmc.ProductData.Offset,hmc.ProductData.Limit).then(function(Products){
if(hmc.ProductData.Page==0)
{
hmc.ProductData.Products[0]='';
}
hmc.ProductData.Page++;
var tempArray=[];
tempArray.push(Products);
console.log(tempArray);
hmc.ProductData.Products [0]=hmc.ProductData.Products [0].concat(tempArray[0]);
console.log(hmc.ProductData.Products );
hmc.ProductData.UpdateInProgress=false;
});
}
but it doesn't contact and merge the array and wouldn't work.

With tempArray.push(Products); you push a single array, considered as the whole variable, in a single cell of the array tempArray without obtaining the expected result. You should call:
tempArray = tempArray.concat(Products);
This way you push every element of Products in tempArray. Please note that concat does not modify the calling array directly, this behavior force you to reassign its return value to the original tempArray.

I Just did it like this:
hmc.ProductData.Page++;
var tempArray=[];
var tempArray2=[];
tempArray.push(AjaxProducts);
tempArray2.push(hmc.ProductData.Products);
hmc.ProductData.Products= tempArray2[0].concat(tempArray[0]);
tempArray.length = 0;
tempArray2.length = 0;
Now angular ng-repeat just repeat in a single array structure and ajax appends to the end of that array

Related

How do I make a copy of the component in Angular?

I am using Angular 5 in my project. I did pagination with use ngx-pagination . I need to do this pagination top and bottom table. I need to make pagination at the top and bottom of the table. I did it this way
<div class="admin-panel__nav-block navigation-block">
<app-table-filter-size (valueChange)="valueChange($event)" [size]="size"></app-table-filter-size>
<pagination-controls class="table-pagination pagination-block" previousLabel="Previous" nextLabel="Next" id="listing_pagination" (pageChange)="pageChange(p = $event)"></pagination-controls>
</div>
<!--Table -->
...
<!--Table End -->
<div class="admin-panel__nav-block navigation-block">
<app-table-filter-size (valueChange)="valueChange($event)" [size]="size"></app-table-filter-size>
<pagination-controls class="table-pagination pagination-block" previousLabel="Previous" nextLabel="Next" id="listing_pagination" (pageChange)="pageChange(p = $event)"></pagination-controls>
</div>
it's working , but it's probably not a good practice, since the same id is used in different places. how can I get rid of duplicate code? What should I do in my situation?
You need to have an id to uniquely identify dynamically assigned instead of having hardcoded id="listing_pagination"
Have a paginationConfig Array and push configs for each set of data
ts file implementation
private paginationConfigs: Array; // define the variable
this.paginationConfigs = []; //initialize in the ngOnInit lifecycle function
Have the below configuration for each dataset probably inside the loop
const pagerConfig = {
id: `pager-${value}`, // value could be any unique identifer
itemsPerPage: 10,
currentPage: 1
};
this.paginationConfigs.push(pagerConfig);
html file implementation
<tr *ngFor="let item of mf.data| paginate: paginationConfigs[i]" >// data display </tr>
<pagination-controls previousLabel="Previous" nextLabel="Next [id]='paginationConfigs[i].id'(pageChange)="pageChange(paginationConfigs[i].currentPage= $event)"></pagination-controls>

Angular: Updating $scope with new data causes old data to remain when using ng-repeat

I'm having a strange issue where I replace the values in $rootScope.data.vehicles with new data but the old data points on my view remain for about one second alongside the new data.
For instance, right after I replace the $rootScope.data.vehicles array with a new array my view will display the 3 new values first followed by the 3 old values. View is using ng-repeat on $rootScope.data.vehicles to display tiles.
About one second later the 3 old values are no longer displayed in the view.
Each time the interval fires I get new values followed by old values, even if the values have not changed.
My controller and factory look like so:
(function () {
var vehiclesInjectParams = ['$location', 'dataService', '$rootScope', 'VehiclesRefreshService'];
var VehiclesController = function ($location, dataService, $rootScope, VehiclesRefreshService) {
var vm = this;
if ($rootScope.data == undefined)
$rootScope.data = {};
$rootScope.data.vehicles = [];
function init() {
dataService.getVehicles()
.then(function (data) {
$rootScope.data.vehicles = data.results;
}, function (error) {
var thisError = error.data.message;
});
VehiclesRefreshService.getValues();
};
init();
};
VehiclesController.$inject = vehiclesInjectParams;
var vehiclesRefreshInjectParams = ['$interval', '$rootScope', '$q', 'dataService'];
var VehiclesRefreshService = function ($interval, $rootScope, $q, dataService) {
var factory = {};
factory.getValues = function () {
var interval = $interval(function () {
dataService.getVehicles()
.then(function (data) {
$rootScope.data.vehicles = data.results;
}, function (error) {
var thisError = error.data.message;
});
}, 10000);
};
return factory;
};
VehiclesRefreshService.$inject = vehiclesRefreshInjectParams;
angular.module('teleAiDiagnostics').controller('VehiclesController', VehiclesController).factory('VehiclesRefreshService', VehiclesRefreshService);
}());
First I load the array then I start an $interval timer to refresh the values every 10 seconds. As soon as the dataService returns the new list of values and puts them in $rootScope.data.vehicles I notice the six tiles instead of 3. One second after that I'm left with only the 3 new tiles.
My view looks like so:
<header>
<h1>Vehicles</h1>
</header>
<article class="icon-gallery flexslider">
<section>
<figure ng-repeat="vehicle in $parent.data.vehicles" class="gallery-item svg">
<a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
<img src="img/machine/01.svg" alt="">
<span class="green-machine-code">{{vehicle.id}}</span>
</a>
<ul>
<li>{{vehicle.id}}</li>
<li>{{vehicle.ip}}</li>
<li>Online: {{vehicle.online}}</li>
<li>Status: {{vehicle.status}}</li>
<li>AllClear: {{vehicle.allClear}}</li>
</ul>
</figure>
</section>
</article>
Any ideas as to how to get my tiles to refresh seamlessly? All help is greatly appreciated.
Avoid track by $index when there is a unique property identifier to work with.
<figure ng-repeat="vehicle in $parent.data.vehicles track by ̲v̲e̲h̲i̲c̲l̲e̲.̲i̲d̲ ̶$̶i̶n̶d̶e̶x̶" class="gallery-item svg">
<a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
<img src="img/machine/01.svg" alt="">
<span class="green-machine-code">{{vehicle.id}}</span>
</a>
<ul>
<li>{{vehicle.id}}</li>
<li>{{vehicle.ip}}</li>
<li>Online: {{vehicle.online}}</li>
<li>Status: {{vehicle.status}}</li>
<li>AllClear: {{vehicle.allClear}}</li>
</ul>
</figure>
From the Docs:
If you are working with objects that have a unique identifier property, you should track by this identifier instead of the object instance. 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.
— AngularJS ng-repeat Directive API Reference - Tracking
Mike Feltman in the comments above resolved the issue. It was as simple as adding 'track by $index' to the ng-repeat tag in the view. See here:
<header>
<h1>Vehicles</h1>
</header>
<article class="icon-gallery flexslider">
<section>
<figure ng-repeat="vehicle in $parent.data.vehicles track by $index" class="gallery-item svg">
<a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
<img src="img/machine/01.svg" alt="">
<span class="green-machine-code">{{vehicle.id}}</span>
</a>
<ul>
<li>{{vehicle.id}}</li>
<li>{{vehicle.ip}}</li>
<li>Online: {{vehicle.online}}</li>
<li>Status: {{vehicle.status}}</li>
<li>AllClear: {{vehicle.allClear}}</li>
</ul>
</figure>
</section>
</article>
Hopefully this post will help someone in the future who is experiencing the same type of problem.
IIRC, internally Angular sees that the vehicles array has changed and immediately renders it, then cleans up. Adding track by $index to the ng-repeat should basically force rendering to start at the first item each time.
I do agree with the other post regarding the use of $rootScope. If you're trying to make the vehicles available globally rather than storing them in rootScope, store them in your data service and inject it whereever necessary. It will be a much cleaner approach.

Vue.js: How to map a list of keys to Firebase objects?

I develop a small web-app based on Vue.js using Firebase to store and sync the data. I store items (e.g. with attributes title and subtitle) and lists with an attribute listitems, where an array of keys (those generated from Firebase) of items is stored. The structure looks like this:
Now the problem: I want to display a list and show the items from the listitems attribute and I'm doing it like this:
Compontent:
var ShowList = Vue.extend({
template: '#show-list',
firebase: {
// get all existing items from firebase
items: firebase.database().ref('items')
},
data: function () {
// get list item keys of list 'list_id' and bind it to this.list
this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
return {
list: this.list
};
}
});
Template:
<!-- show a list -->
<template id="show-list">
<ul v-if="list.items != ''">
<li v-for="key in list.items"> <!-- I would like to not being forced to -->
<template v-for="item in items"> <!-- iterate the whole list of existing items -->
<span v-if="item['.key'] == key">
{{ item.title }}
</span>
</template>
</li>
</ul>
<div v-else>No items.</div>
</template>
As you can see, I have to use two iterations where I iterate the full items list for every entry in list.items.
My question: Is there a more efficient way to map the actual objects to the list of object keys? For a huge number of item records, my approach will be very slow. Maybe I'm just too blind to see a simpler solution?
Thanks for your time!
I think you have to denormalize/duplicate some data there. I had a similar situation and this Firebase video cleared a lot of things up for me: https://youtu.be/ran_Ylug7AE?t=2m22s (Link updated to passage at 2:22. The whole serie is worth watching btw.)
My shot at it would be adding (Firebase) keys in "listitems", just like you have done in "items", with only the most crucial data there, so that you can link to a full description
Is your data read only? In which case you could move the filter logic from your template to your data module, like so (I expect I have unintended side-effects):
data: function () {
// get list item keys of list 'list_id' and bind it to this.list
this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
var items = firebase.database().ref('items')
var activeItems = this.list.items.map(function(key) {
return items[key]
})
return {
activeItems: activeItems;
};
}

ng-repeat appending data multiple times

HTML
<div ng-app="templeApp" ng-controller="templeList">
<div ng-repeat="temple in temples track by $index" >
<h2>{{temple.strTempleName}}</h2>
<h4>{{temple.strTempleDescription}}</h4>
<h4>5km from current location</h4>
</div>
</div>
JS
var templeApp = angular.module('templeApp', [])
.controller('templeList',function($scope,$http){
$scope.temples = [{"_id":"new","strTempleName":"Temple 1 Name","strTempleDescription":"Temple 1 description","strContactNumber":"+91899999999","strTempleLocation":"Chennai","iTempleRating":5,"strContactPersonName":"","strTempleCoordinates":""}] ;
$http.get("https://gist.githubusercontent.com/vigneshvdm/d106ea482a792c60dff8/raw/c8f020eb54c4068e40884b8d84c972d92e8e4e08/vicky%20test%20file").success(function(data){
$scope.temples = data[0]; //uncomment this line to see error
console.log(data[0]);
});
});
PROBLEM
When i comment the $scope.temples = data[0]; line, ne-repeat is appending data only once, but when i assign the data to $scope.temples its appending same data multiple time
DEMO LINK
remove track by $index in ng-repeat and change the below like this
in this example i used temple.strTempleName for track by filter make sure it is return unique names.
<div ng-app="templeApp" ng-controller="templeList">
<div ng-repeat="temple in temples track by temple.strTempleName" >
<h2>{{temple.strTempleName}}</h2>
<h4>{{temple.strTempleDescription}}</h4>
<h4>5km from current location</h4>
</div>
</div>

How to add Contact List data into PhoneGap ListView

I have a javascript function which will read the device ContactList and add them into a javascript array.In my HTML page i have taken a listview.Now as per my requirement i have to add these array data into the listview by jquery dynamically which i am not able to do .I am not able to see anything on the screen of the mobile on launching the app..
Here is my javascript code to read from Mobile's contact list..
function onDeviceReady() {
// specify contact search criteria
var options = new ContactFindOptions();
options.filter=""; // empty search string returns all contacts
options.multiple=true; // return multiple results
filter = ["displayName"]; // return contact.displayName field
// find contacts
navigator.contacts.find(filter, onSuccess, onError, options);
}
var names = [];
// onSuccess: Get a snapshot of the current contacts
//
function onSuccess(contacts) {
for (var i=0; i<contacts.length; i++) {
if (contacts[i].displayName) { // many contacts don't have displayName
names.push(contacts[i].displayName);
}
}
alert('contacts loaded');
}
and here is my HTML listview..
<div data-role="page" id="home" data-theme="c">
<div data-role="content">
<div id="header" class="header">
<h1>Contact Directory</h1>
</div>
<ul data-role="listview" id="contactlist" data-theme="a">
</ul>
</div>
</div>
So, My question is how can i add the array values into the listview by jquery dynamically..
Thanks..
Couple of ways, but here is one way.
Create a simple string variable to hold your LIs.
Loop over names and append to the string <li> + names[x] + </li> where X is your loop counter.
Use jQuery to get the UL dom and then do .html(s) where s is your string.
Basically you are injecting <li>...</li><li>...</li> into your UL.
The last step is to refresh the list view so jQuery displays it correctly. This is done with the refresh API, defined here: http://api.jquerymobile.com/listview/#method-refresh

Categories

Resources