Vue.js array is mixed up after reloading data - arrays

The data in the Vue.js array with JSON objects in it is mixed up after reloading them from Spring backend.
I am trying to make a frontend with Vue.js for editing the data on the Spring backend. Vue.js makes a call to the backend with axios, it returns a list of items that is rendered on the page with a v-for. The items can be edited separately, when the 'Save' button is clicked for an item, the item is sent to the backend and the data is updated in the database. After this, when I hit reload in the browser (or close and open the same page) the data is reloaded from the server but its mixed up.
loadExercises(){
axios({url:'http://localhost:5000/exercises/all'}).then(resp => {
this.exercises = resp.data;
})
}
This is the function that loads the data.
This is the array originally : https://imgur.com/5x8TiwY
This is the array after reload, I edited the first entry: https://imgur.com/d6G4SMm
The backend returns the correct objects, the only difference is the that
the entry which was edited is the last in the array (and it was the first in the example case before the edit). The id-s do not change during saving, just the details are updated, like name or description.
This is the part of the template that generates the html, just in case it is because something in there.
<div role="tablist" id="container" v-bind:key="ex.id" v-for="ex in exercises">
<b-card no-body class="mb-1 customcard">
<b-card-header header-tag="header" class="p-1 alignleft" role="tab" v-b-toggle="`accordion${ex.id}`">
<span>{{ex.name}}</span>
</b-card-header>
<b-collapse v-bind:id="`accordion${ex.id}`" accordion="my-accordion" role="tabpanel">
<b-card-body class = "alignleft">
<p class="card-text">
Name: <b-form-input
v-bind:value="`${ex.name}`"
v-bind:id="`input${ex.id}`"
v-on:input="saveExName(ex.id)"></b-form-input>
Target: {{ex.target}} <b-form-select v-on:input="onTargetChange(ex.id)"
v-bind:id="`target${ex.id}`" >
<option v-bind:key = "target" v-for="target in targets" :value="target" >{{target}}</option>
</b-form-select>
Description: <b-form-textarea
v-bind:value="`${ex.description}`"
:rows="3"
:max-rows="6"
v-on:input="saveExDesc(ex.id)"
v-bind:id="`textarea${ex.id}`"></b-form-textarea>
</p>
<div class="alignright">
<b-button v-on:click="saveExUpdate(ex.id)">Save</b-button>
</div>
</b-card-body>
</b-collapse>
</b-card>
</div>
Any ideas why this is happening?

Related

Looping over array of objects to populate carousels in array of cards in angular

i have an array of objects composed of objects (id,image), and i also have several cards as result of my fetch to the backend.
What im trying to do is on every card establish a carousel exclusively with the images that match with the id the card has in fact , lets say this is my array of images
arrayOfImages:[
{id: "1",image: "xxxxxxxxxx"},
{id: "1",image: "xxxxxxxxxx"},
{id: "2",image: "xxxxxxxxxx"},
{id: "2",image: "xxxxxxxxxx"},
{id: "1",image: "xxxxxxxxxx"},
{id: "2",image: "xxxxxxxxxx"}
]
Lets say then on my html tag in angular i trigger the html :
<div *ngFor="let post of allPortafolio;let i=index">
//NgFor that bring me all cards from back
//some code
<ngb-carousel>
//carousel specific for one card where in i want to loop over the array of images
<ng-template ngbSlide *ngFor="let image of arrayOfImages">
<img *ngIf="post.id===image.id;else alternative" [src]="image.image">
<ng-template #alternative>
<img " else src="../../../assets/white.jpg">
</ng-template>
</ng-template>
</ngb-carousel>
</div>
As you could see , had to use an else , using other fixed template while the loops keeps its course not matching the id conditions, but the aesthetic is horrible, cause seems like if the page where in constant fetch recharge , instead of having a smooth flow in the carousel.
But i was wondering if there was another alternative where i could witouth using an else could loop over that array of objects and asign to every card its respective images with the matching id's to the card in fact, thus then their respective carousels would flow perfect without interruptions
A better way to achieve what you want is to create a function in you typescript file where you match the id of a post with the id an image and return either a matching image or a generic image.
matchImage(post, image) {
if (post.id === image.id) {
return image.image
} else {
return '../../../assets/white.jpg'
}
}
and in your html file:
<div *ngFor="let post of allPortafolio;let i=index">
//NgFor that bring me all cards from back
//some code
<ngb-carousel>
//carousel specific for one card where in i want to loop over the array of images
<ng-template ngbSlide *ngFor="let image of arrayOfImages">
<img [src]="matchImage(post, image)">
</ng-template>
</ngb-carousel>
</div>
if you want a stackblitz demo, just make a small reproducible demo of you problem and I will be glad to modify it with this solution.

Filtering MongoDB data on the front end

I have little problems with MongoDb. I have 2 collections: Auctions and Users. In the "Users" i store obviously the users (mail, name...etc) In the Auctions i store products (creationdate, createdBy, FollowedBy, Invitations, image). Now, i want to show in every user's dashboard, only the products that he follows (his name is stored in the ""FOllowedBy" when he clicks on the botton Follow). If I have to filter on the backend, all it's clear, instead i want to load all the data from the DB and then filter that on the front end with angularJs.
With a simple field like createdBy it's easy: If i Have an user called "Alex"(for example) i can show the data only if createdBy match with Alex (or every other user). But the same thing doesn't work with an array field like "FollowedBy". If in the product "Table" createdby: "Mark", FollowedBy: "Alex" and "Jack", i can easy filter all the product to show only Mark's product, but i don't understand how to show only the products followed by Alex, cause this field is an array.
This is my back-end route.
app.get('/api/dashboard', function (req, res) {
AllAuctions
.find({}, function (err, auctions) {
if (err)
res.send(err);
console.log(auctions);
res.send(auctions);
});
});
I load it with $http with angularJs:
$http.get('/api/dashboard').then(function (AllAuctions) {
$scope.allauctions = AllAuctions.data;
});
If i have to filter the field "createdBy" i can do something like this:
<div class="panel panel-default" >
<div class="panel-heading">My Auctions</div>
<div class="panel-body">
<ul class="list-group" ng-repeat="allauction in allauctions">
<li class="list-group-item" ng-show="allauction.createdBy=='Alex'">
<img ng-src="{{allauction.imgUrl}}">
<div class="title"> {{allauction.title}} </div>
</li>
</ul>
</div>
</div>
But i don't understand how to filter a field like this:
FollowedBy: [
Shelly.name,
Dario.name
]
to show only the products followed by Dario.
If you want to do it in html you can do something like
ng-show="allauction.FollowedBy.indexOf('Alex')>=0"
However when you have multiple filters it will quickly become hardcore. You should define a filtering function in javascript that will compute a filtered array on which you can do a simple ng-repeat. Or you could alternatively add a flag to your allauction objects and perform ng-if/ng-show based on this flag. For exemple:
function updateFilteredData()
{
$scope.filteredData = [];
for(var i = 0; i< $scope.allauction; i++)
{
var auction = $scope.allauction[i];
if(auction.createdBy !== currentUser.name) //I assume currentUser is json object for your Alex user
continue;
if($scope.followByFilter && auction.FollowedBy.indexOf($scope.followByFilter) < 0)
continue; //I assume followByFilter is a string containing the name of a follower you are trying to filter
$scope.filteredData.push(auction);
}
}
You need to call this function once in $http get and each time filtering conditions change (ex: followByFilter name changes...).
Ofcorse you should ng-repeat on filteredData array instead of allauction.

Angular: ng-repeat (possibly $$hashkey) affecting array lookup

Im trying to implement a shopping car solution through angular that will enable a customer to select menus items from a list of items displayed within an <ng-repeat>. These menu items are represented as objects and I store these list of menu item objects in a shopping cart array. Any time a user clicks on the '+' button I have created, an item in included in the cart order array (or increase the order quantity if it already exist), and the view is updated to also include a '-' button to decrement the order. Thus, implicitly, I have a function that checks whether or not the item in the order array in my cart service. All is fine and good until I refresh the page. The cart is instantiated from a cookie. And the cart has the correct items, but the '-' decrement button does not show up next to items that have been selected in the cart. Below is my code.
html partial
<div class="col-xs-4">
<p>
{{category.items[$index].price | currency}}
<a ng-click="menu.addMenuItem(category.items[$index])"> <span class="plus glyphicon glyphicon-plus"></span></a>
<span ng-show="menu.getItemQuantity(category.items[$index])"> <!-- this does not work on refresh-->
{{menu.getItemQuantity(category.items[$index])}}
<a ng-click="menu.subMenuItem(category.items[$index])"> <span class="minus glyphicon glyphicon-minus"></span></a>
</span>
</p>
</div>
relevant controller functions
vm = this;
vm.getItemQuantity = function(item){ //always returns 0 on page refresh
return shoppingCart.getItemQuantity(item);
};
relevant cart service functions
var cart = {};
cart.order=[];
var addItemToOrder = function(item){
var inOrder=isItemInOrder(item);
if(inOrder.check){
cart.order[inOrder.index].quantity+=1;
}else{
var orderItem={
item:item,
quantity:1
};
cart.order.push(orderItem);
}
setCartCookie();
};
//always initially returns check property equal to false on page refresh, although cart is instantiated from cookie
var isItemInOrder = function(item){
for(var i=0; i<cart.order.length; i++){
if(cart.order[i].item==item){
console.log('item in order list');
return {check:true, index:i};
}
}
return {check:false};
};
//more functions
It seems like my issues may be due to this thing $$hashkey that gets added as a property to my menu items, but im not sure what to do. Can someone help resolve this. The application works great till the app is refreshed. The menu item on the page does not display a '-' button.
update
I have taken a picture from chrome tools and it seems like two identical objects that have been separately instantiated are not equating. Is this normal?

How to retrieve nested json object data with Ionic

I am working with the api from The Movie Database. In my Ionic project I was able to make a http request to pull in some data for a movie. However the json object is a nested json object, so I am having some trouble trying to access the genres of a movie:
For the purpose of this question I will display 1 nested json object:
I want to show the information like so -> Genre: Action - Comedy - Drama
My code for the controller is the following:
$scope.init = function(){
MovieService.getMovieById($stateParams.id).then(function(data){
$scope.trending_movie = data;
console.log($scope.trending_movie);
$scope.genres = data.genres;
console.log($scope.genres);
});
}
If I do this bit of code:
$scope.genres = data.genres;
It just returns met the json object of the genres like so:
The thing is now that I am able to read out the genres but because I access the data with a ng-repeat it will show like this:
How to get the genres on 1 line without having to repeat the word "Genre"?
Here is my html code:
<div ng-repeat="genre in genres">
<p class="movie-info-p">Genre: {{genre.name}}</p>
</div>
you should get "Genre:" out of your ng-repeat and if you want your genres to be in the same line, you shouldn't put them in tag.
There is this solution:
<div> Genre:
<div ng-repeat="genre in genres">
<span class="movie-info-p">{{genre.name}}</span>
</div>
</div>
Another solution is to generate this string in the controller with a for loop and send it to the view

Angular ng-bind-html makes template rendering very slow

I am trying to output a list of jobs each having their description in HTML,
but adding the data-ng-bind-html="job.description" directive makes the template rendering very slow - more than 10 seconds.
The jobs are being returned from the server as JSON e.g.
foreach ($jobs as $j) {
$data_arr[] = [
'ID' => $j->ID,
'title' => $j->post_title,
'description' => $j->post_content, // contains HTML
...
]}
// ... return json data
The controller looks something like this
api.getJobs().success(function (data) {
$scope.jobs = data;
});
The template setup it is something like this
<div data-ng-repeat="job in jobs">
<div>{{job.title}}</div>
<div data-ng-bind-html="job.description"></div>
</div>
If I comment out the data-ng-bind-html the template renders fast.
I am only rendering 25 jobs and the HTML is just a few strong and li tags not sure why it is so slow.
Update,
It appears that data-ng-bind-html is a slow operation, finally what worked for me is to only render per job html after some action has been taken by the user.
In my case when the bootstrap accordion containing the job is expanded.
<div data-ng-if="status.open" data-ng-bind-html="job.description"></div>

Resources