ng-repeat for carousel: data not updated or refreshed - javascript

Iam not getting slick carousel with updated data when i update this ng-repeat data of slider from my controller.
<slick lazyLoad=ondemand init-onload=true slides-to-show=5 slides-to-scroll=1 next-arrow=".rightOne" prev-arrow=".leftOne" data="trailersUpcomming">
<div index="$index " ng-repeat="trailer in trailersUpcomming ">
<div class=" boxhover testimonialslider" style="margin-right: 12px; ">
<div class="card " style="border-color: green; ">
<div style="padding: 17px;text-align: left;height: 124px;background-color: #ffffff;">
<div>ReleaseDate : {{trailer.releasedate}}</div>
<div>Language : {{trailer.filmlanguage}}</div>
<div>Rating : {{trailer.filmrating}}</div>
</div>
</div>
</div>
</div>
</slick>

Try to update your array scope by using angular.copy
for reference please refer this example angular slick update example

The place there you are updating your data just use
$timeout(function(){
//update your variable here.
}

I had faced similar issue. Using angular's old version i.e. 1.4 and using slider carousel. On refresh/page reload carousel was not getting refreshed with latest data.
$('.slider').slick('reinit'); or $('.slider').slick('refresh');
did not work me so I had to play with data coming from server into angular client.
Did fix that with no so great solution but it worked for me.
What I observed is that, the array which is used to iterate and display elements in it on the carousel do not work if its reference changes on page reload. If you directly do not assign data array to the target array whose elements are being shown on Carousel then it works.
For that, I am using array's Push() method
for (let i=0; i < data.length ; i++) {
var id = vm.targetArray.length + 1;
if ( vm.targetArray.filter(item=> item.name == data[i].name).length == 0){
vm.targetArray.push(data[i]);
console.log("Pushed the item to targetArray : " + data[i].name);
}
}

Related

Reload Data with .sort from Dynamic Table with Jquery | JSON | Sort with New Data

I have been trying for a few days that when I use the .sort property the data is eliminated or modified instead of it being reloaded as new lines.
Attach Captures from the code Working
Image1 How work the code when i press the button, this sort to the highest price to lowest but how do you can see in the second image, the code appears up and this not delete the old data
Marked with "X" the data that does not have to show
this fragment is the one that generates the tables dynamically
const mostrarProductos = () => {
$.getJSON(URLJSON, (respuesta) => {
for (let z of respuesta) {
productosv2.push(z);
}
for (let x of productosv2) {
$("#fila").append(`
<tr class="deleteProductos">
<div class="card text-center" style="width: 18rem;" id='btnBorrarCarrito'>
<div class="card-body">
<input type="hidden" id="idProd" value="${x.id}"> </td>
<td class="card-title" id="${x.id}">${x.producto}</h2> </td>
<td class="card-text">$ ${x.precio}</p></td>
<div class="btn-group" role="group" aria-label="Basic mixed styles example">
<td><button type="button" class="btn btn-success" onclick="agregarCarrito(${x.id})">Agregar</button></td>
</div>
</div>
</div>
</tr>
`);
}
$("#fila").fadeIn("5000");
});
};
And this function is what orders them
function respuestaClickExpensive() {
$("#fila").html('');
let productosordenados = productosv2.sort((a, b) => {
if (a.precio > b.precio) {
return -1;
}
if (a.precio < b.precio) {
return 1;
}
return 0;
});
return productosordenados;
}
The one that orders them from smallest to largest is the same only that different signs and names.
As you can see I tried to use a ".html ("")" since previously in another cart attempt it used .innerHtml (Which does not work in this case either, Also the code of the cart is totally different from that moment that it worked for me
)
I tried the following:
$ ("#fila"). empty ();
Make another function to clean with .empty
Use Native JavaScript to generate the code.
$ ("#fila"). remove (); this removes all the content for me but does not regenerate it.
Change the HTML tag "Row" to a previous div which, since the div was not generated again, did not generate it again.
$ ("#fila tr"). remove ();
And some more things that I don't remember right now.
If you can guide me on what I did wrong or any suggestions to fix it, I appreciate it.
If I had to follow a template about posting on StackOverFlow or having chosen or named in a different way, I appreciate your comment since it is my first post
Project notes of possible relevance: The complete code outside of html and css is made with Native JavaScript, Jquery, Ajax, SASS and BootStrap.

How to make ko.sortable work with ko.computed

I am using knockout and Ryan Niemeyers ko.sortable.
My aim is to move items from one container to another. This works nice.
However, due to other circumstances I want the observableArrays object to be drag´n´dropped to be ko.computed.
I have a basic array containing all my elements
self.Textbatches = ko.observableArray();
then I have a filter version
self.TextsTypeOne = ko.computed(function(){
return ko.utils.arrayFilter(self.Textbatches(),function(t){
return t.type() === '1';
});
});
I have another filtered list with the texts dragging:
self.allocationableTextbatches = ko.computed(function(){
return ko.utils.arrayFilter(self.Textbatches(),function(t){
return t.type() === null;
});
});
Then I create my two containers with ´self.TextsTypeOne´ and ´self.allocationableTextbatches´:
<div id="allocationable-texts" class="menupanel">
<h4 class="select">Text(s) to allocate:</h4>
<div class="tb-table">
<div class="tb-list" data-bind="sortable:{template:'textbatchTmpl',data:$root.allocationableTextbatches,allowDrop:true}"></div>
</div>
</div>
<div id="TypeOne-texts" class="menupanel">
<h4 class="select">Text(s) on scene:</h4>
<div class="tb-table">
<div class="tb-list" data-bind="sortable:{template:'textbatchTmpl',data:$root.TextsTypeOne,allowDrop:true}"></div>
</div>
</div>
where
<script id="textbatchTmpl" type="text/html"><div class="textbatch" data-bind="click: $root.selectedText">
<span class="tb-title" data-bind="text: title"></span>
I can easily add buttons to my template setting type to 'null' and '1' respectively, and make it work that way. However I want this to be a drag and drop feature (as well) and the ko.sortable works on the jquery-ui objects. Thus it needs ´ordinary´ ´ko.observableArrays´ and not ´ko.computed´s as it is 'splice´-ing the observableArray, and dragging and dropping results in an error "TypeError: k.splice is not a function".
I have tried to make ´self.allocationableTextbatches´ and ´self.TextsTypeOne´ writable computed, but to no avail.
Any help and suggestions is highly appreciable!
Thanks in advance!

What's the best way to append an element using angular?

My objective is to show a grid of products and ads between them.
warehouse.query({limit: limit, skip: skip}).$promise
.then(function(data) {
for (var i = 0; i < data.length; i++) {
var auxDate = new Date(data[i].date);
data[i].date = auxDate.toISOString();
}
Array.prototype.push.apply($scope.products, data);
//add an img ad
var warehouseElem = angular.element(document.getElementsByClassName('warehouse')[0]);
var newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');
warehouseElem.append(newAd);
skip += 9
});
Doesn't work.
I already tried simply using pure javascript like,
var warehouseElem = document.getElementsByClassName('warehouse')[0];
var newAd = document.createElement('img');
warehouseElem.appendChild(newAd);
Also doesn't work.
I suppose I need to do something with angular, can't find out what. I think it's sanitize but maybe I just don't know how to use it.
Remember I need to inject an img every once in a while between products.
This is a job for ng-repeat!
<div ng-repeat="data in datas">
<div>[show data here]</div>
<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
If you have bind your "datas" in scope and Math too like this in your controller like this it should works
$scope.datas // this is your list of products
$scope.Math = Math;
If you don't want to spam add for each line you can use ng-if with $index like this :
<div ng-if="$index%2==0">
<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
This will make it display add every 2 lines.
Since you seemed to come from a jQuery-like (or native DOM manipulation) background, I suggest you to read that post : "Thinking in AngularJS" if I have a jQuery background?.
This will explain you why in angular you almost don't manipulate DOM and quite some other things (only in directives).
EDIT : to fix the grid problem, just merging my two html block build your array of datas like this :
$scope.myArray = [product[0], ad[0] or just an empty string it will work still, product[1], ad[1]]
And the html
<div ng-repeat="data in datas">
<div ng-if="$index%2==0">[show data here]</div>
<img ng-if="$index%2==1 src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
In AngularJS you should generally avoid doing DOM manipulation directly and rather rely on angular directives like ng-show/ng-hide and ng-if to dynamically hide sections of a template according to the specific case.
Now back to the problem at hand.
Assuming that you are trying to render a list of products loaded with the code displayed above and display an ad for some of them, you can try the following.
<!-- place the img element in your template instead of appending -->
<div ng-repeat="product in products">
<!-- complex product template-->
<!-- use ng-if to control which products should have an ad -->
<img ng-src="product.adUrl" ng-if="product.adUrl" />
</div>
Then in your controller set adUrl for products that should have an ad displayed.
warehouse.query({limit: limit, skip: skip}).$promise
.then(function(data) {
for (var i = 0; i < data.length; i++) {
var hasAd = // set to true if this product should have an add or not
var auxDate = new Date(data[i].date);
data[i].date = auxDate.toISOString();
if(hasAd){
data.adUrl = "/ad/?r=" + Math.floor(Math.random()*1000);
}
}
Array.prototype.push.apply($scope.products, data);
skip += 9
});
I am most probably assuming too much. If that is the case please provide more details for your specific case.
If you declare a scope variable,
$scope.newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');
and in your HTML template, have a binding like
<div ng-bind-html="newAd"></div>,
it should work.

Update unrelated field when clicking Angular checkbox

I have a list of checkboxes for people, and I need to trigger an event that will display information about each person selected in another area of the view. I am getting the event to run in my controller and updating the array of staff information. However, the view is not updated with this information. I think this is probably some kind of scope issue, but cannot find anything that works. I have tried adding a $watch, my code seems to think that is already running. I have also tried adding a directive, but nothing in there seems to make this work any better. I am very, very new to Angular and do not know where to look for help on this.
My view includes the following:
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<fieldset>
<p data-ng-repeat="person in staffCtrl.persons">
<input type="checkbox" name="selectedPersons" value="{{ physician.StaffNumber }}" data-ng-model="person.isSelected"
data-ng-checked="isSelected(person.StaffNumber)" data-ng-change="staffCtrl.toggleSelection(person.StaffNumber)" />
{{ person.LastName }}, {{ person.FirstName }}<br />
</p>
</fieldset>
</div>
<div data-ng-controller="staffController as staffCtrl">
# of items: <span data-ng-bind="staffCtrl.infoList.length"></span>
<ul>
<li data-ng-repeat="info in staffCtrl.infoList">
<span data-ng-bind="info.staffInfoItem1"></span>
</li>
</ul>
</div>
My controller includes the following:
function getStaffInfo(staffId, date) {
staffService.getStaffInfoById(staffId)
.then(success)
.catch(failed);
function success(data) {
if (!self.infoList.length > 0) {
self.infoList = [];
}
var staffItems = { staffId: staffNumber, info: data };
self.infoList.push(staffItems);
}
function failed(err) {
self.errorMessage = err;
}
}
self.toggleSelection = function toggleSelection(staffId) {
var idx = self.selectedStaff.indexOf(staffId);
// is currently selected
if (idx >= 0) {
self.selectedStaff.splice(idx, 1);
removeInfoForStaff(staffId);
} else {
self.selectedStaff.push(staffId);
getStaffInfo(staffId);
}
};
Thanks in advance!!
In the code you posted, there are two main problems. One in the template, and one in the controller logic.
Your template is the following :
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<!-- ngRepeat where you select the persons -->
</div>
<div data-ng-controller="staffController as staffCtrl">
<!-- ngRepeat where you show persons info -->
</div>
Here, you declared twice the controller, therefore, you have two instances of it. When you select the persons, you are storing the info in the data structures of the first instance. But the part of the view that displays the infos is working with other instances of the data structures, that are undefined or empty. The controller should be declared on a parent element of the two divs.
The second mistake is the following :
if (!self.infoList.length > 0) {
self.infoList = [];
}
You probably meant :
if (!self.infoList) {
self.infoList = [];
}
which could be rewrited as :
self.infoList = self.infoList || [];

Conditionally bind data in AngularJS

I have an array of tasks. They have titles and and labels.
function Task(taskTitle, taskType) {
this.title = taskTitle;
this.type = taskType;
}
$scope.tasks = [];
I end up declaring a bunch of tasks with different types and adding them to the array
In my html, I show a column of cards, filtered by type of task:
<div ng-model="tasks">
<div class="card" ng-repeat="abc in tasks track by $index" ng-show="abc.type==0">
<p> {{ abc.title }} </p>
</div>
</div>
I want to bind the first card displayed in this filtered view to some other div. I'll be processing an inbox, so I'll whittle this list of cards down to zero. Each time I 'process' a card and remove it from the list, I need the data to refresh.
<div ng-model="firstCardInFilteredArray">
<h4>Title of first card:</h4>
<p> This should be the title of the first card! </p>
</div>
My intuition was to do something like this (in javascript):
// pseudo-code!
$scope.inboxTasks = [];
for (i=0; i<tasks.length(); i++) {
if (tasks[i].type == 0) {
inboxTasks.append(tasks[i]);
}
}
and somehow run that function again any time the page changes. But that seems ridiculous, and not within the spirit of Angular.
Is there a simple way in pure javascript or with Angular that I can accomplish this conditional binding?
You can filter your ng-repeat: https://docs.angularjs.org/api/ng/filter/filter
<div ng-model="tasks">
<div class="card" ng-repeat="abc in filteredData = (tasks | filter: {type==0}) track by $index">
<p> {{ abc.title }} </p>
</div>
</div>
Additionally, by saving the filtered data in a separate list you can display the next task like this:
<div>
<h4>Title of first card:</h4>
<p> filteredData[0].title </p>
</div>
Your data will automatically update as you "process" tasks.
The other answers helped point me in the right direction, but here's how I got it to work:
HTML
<input ng-model="inboxEditTitle" />
JS
$scope.filteredArray = [];
$scope.$watch('tasks',function(){
$scope.filteredArray = filterFilter($scope.tasks, {type:0});
$scope.inboxEditTitle = $scope.filteredArray[0].title;
},true); // the 'true' keyword is the kicker
Setting the third argument of $watch to true means that any changes to any data in my tasks array triggers the watch function. This is what's known as an equality watch, which is apparently more computationally intensive, but is what I need.
This SO question and answer has helpful commentary on a similar problem, and a great fiddle as well.
More on different $watch functionality in Angular
To update inboxTasks, you could use $watchCollection:
$scope.inboxTasks = [];
$scope.$watchCollection('tasks', function(newTasks, oldTasks)
{
for (i=0; i<newTasks.length(); i++)
{
if(newTasks[i].type == 0)
{
$scope.inboxTasks.append(tasks[i]);
}
}
});

Categories