Angular - Use $index to load product images - javascript

I have the following form in my AngularJS app:
<li ng-repeat="device in devices track by $index">
<div class="db-handset-image">
<span class="phone-silhouette"></span>
{{ relative image here }}
</div>
<div class="db-device">
<ul class="opts">
<li>
<select name="manufacturer[ [[$index]] ]" ng-model="selectedManufacturer" ng-change="getManufacturerModels(selectedManufacturer)">
<option value="">Manufacturer</option>
<option ng-repeat="manufacturer in manufacturers" value="[[manufacturer.id]]">[[manufacturer.name]]</option>
</select>
</li>
<li>
<select name="device[ [[$index]] ]" ng-model="selectedModel" ng-change="loadModelImage(selectedModel, $index)">
<option value="">Model</option>
<option ng-repeat="model in manufacturerModels" value="[[model.id]]">[[model.model + ' ' + model.variants[$index].memory + ' ' + model.variants[$index].colour]]</option>
</select>
</li>
</ul>
</div>
</li>
What happens in this form is that a user will select a manufacturer from the first dropdown and a model from the model dropdown. The model dropdown will populate with the relative models after a manufacturer has been selected using Angular's $filter.
When the user has selected a model, loadModelImage is fired and what needs to happen here is that after a model selection, that model image is then loaded into the {{relative image here}} placeholder. This is currently being done like so:
$scope.loadModelImage = function (modelId, $index) {
$http.get(ajaxurl + '?action=get_handset&hid=' + modelId)
.success(function (data) {
$scope.selectedHandsets++;
$scope.modelImages.splice(0, 0, data.handset.images);
})
}
This issue with this is that if I replace the relative image here placeholder text with an <img> loading in the model images, each model that's been selected appears in every row.
My other issue is that if you remain on the same 'row' (see below screenshot) and change the handset image, another array of images is pushed to $scope.modelImages when it in fact the images for that 'row' should effectively be overwritten with the new selection.
To give you a clear understanding of how the form looks, here's a screenshot:
When you click 'add new handset' the row containing the dropdowns is visually duplicated and you can add select another handset.
I hope my problem's explained clearly enough, any Q's ask.

Related

how to show/hide div based on drop down selection using angular?

i want to show and hide a div based on selection from the drop down , here is my code, this is my html code for dropdown which fetches the values from the "selectItemsFilterCriteria" json structure
<select ng-model="appointment" ng-change="changeme()" ng-options="item.name for item in selectItemsFilterCriteria">
<option ng-option value="" >Filter Criteria</option>
</select>
this is my changeme() function created inside a controller
$scope.changeme = function() {
$scope.appointment = $scope.items[0];
}
this is code for my div that is to be show or hide , right now my code is working on selection of first option from drop down it is showing me the div but the problem is that its not hiding that div on the selection of any other option from the dropdown list, kindly tell me where i m doing wrong??
<div class="mycontainer" ng-show=appointment >
<div class="left-nav">
<accordion close-others="true">
<accordion-group ng-repeat="item in pagedItems[currentPage] |filter:{name:item.name}| orderBy:sortingOrder:reverse">
<accordion-heading>
<table>
<tr class="odd" ng-click="showDataDetail=!showDataDetail" style="cursor: pointer">
<td><p class="lead-name">{{item.name}}</p>
<p class="call-up-icon">{{item.phoneNo}} </p>
<p>Lead Date : 07/02/2015</p></td>
<td><p></p>
<p class="blue-txt">{{item.trade}}</p>
<p class="fl cstm-wdth">GNU09</p>
<p class="fl">{{item.time}}</p>
<div class="cb"></div>
</td>
<td><p>Today</p>
<p>C#SQL</p>
<p class="blue-remark-icon"></p></td>
</tr>
</table>
</accordion-heading>
<div>{{item.data}}</div>
</accordion-group>
</accordion>
</div>
</div>
items array:
$scope.selectItemsFilterCriteria = [
{id:1 , name:"Appointments Scheduled"},
{id:2 , name:"fresh leads"}
];
Basically the problem is with your ng-change function call,
$scope.changeme = function() {
$scope.appointment = $scope.items[0];
}
You are setting appointment to first value of items array. Hence whenever you change the options, the function sets it back to first option , in turn the div is shown.
Please remove the ng-change function and try.
Remove the $scope.changeme() function. It is not necessary.
Since you are using ng-model on select whatever option you select will get assigned to the ng-model i.e appointment in your case.
Here is the plunkr example

Editing property from Object in ng-repeat from LocalStorage

I'm listing an array of objects saved into Localstorage in a table-like layout.
Each row displays data saved in a particular object. I want to be able to edit and update certain properties from the object once it has already been saved into LocalStorage.
This is how a couple of my objects looks like:
[{
"date":"2014 10 16",
"time":"20.22",
"car":"396",
"driver":"Seb",
"from":"A",
"destination":"B",
"pax":"3",
"arrival":"23.10"
},
{
"date":"2014 10 16",
"time":"23.22",
"car":"46",
"driver":"Eric",
"from":"C",
"destination":"E",
"pax":"3",
"arrival":"00.10"
}]
So far my frontend code displaying the Destination property looks like this:
HTML
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">{{record.destination}}</div>
// Shows current value
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
// Shows select with options to be picked to update property
<div class="col-md-1">
<button ng-click="editItem = !editItem"
ng-show="!editItem">Edit</button>
<button ng-click="editData(record); editItem = !editItem"
ng-show="editItem">Ok</button>
</div>
//Toggles between current value and select and triggers editData function
Relevant JS:
$scope.editData = function (record) {
record.destination = $scope.locationList2;
jsonToRecordLocalStorage($scope.recordlist);
}
So far when I trigger editData it just deletes the Destination property, it doesn't update it with the model of locationList2 from the Select.
What am I missing?
EDIT
Here's the complete ng-repeat piece of code:
<div class="row msf-row" ng-repeat="record in recordlist | filter: search">
<div class="col-md-1">{{record.time}}</div>
<div class="col-md-1"><strong>{{record.car}}</strong></div>
<div class="col-md-1">{{record.driver}}</div>
<div class="col-md-3">{{record.from}}</div>
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">
{{record.destination}}
</div>
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
<div class="col-md-1">{{record.pax}}</div>
<div class="col-md-1">
<button
ng-click="editItem = !editItem"
ng-show="!editItem">
<i class="fa fa-pencil"></i>
</button>
<button
ng-click="editData(record); editItem = !editItem"
ng-show="editItem">
<i class="fa fa-check"></i>
</button>
</div>
</div>
Also, I here's a Plunkr to ilustrate the issue!
Add a driver, car code and location before starting to see the app running and the mentioned problem.
You could use angular-local-storage as an abstraction over LocalStorage API.
If you want to just hack it, you can do something along localStorage.setItem('data', JSON.stringify(data)) when setting data and use JSON.parse(localStorage.getItem('data')) to extract it. LocalStorage doesn't deal with objects by default so we have to serialize it.
Regardless of the solution you choose, it could be a good idea to extend your edit a bit:
$scope.editData = function (recordlist) {
$scope.recordlist.destination = $scope.locationList2;
// replace whole LocalStorage data here now. no need to "patch" it
updateLocalStorage('data', <data containing your objects goes here>);
}
If you have multiple ways to modify the data and want to avoid explicit update, you could set up a watcher instead:
$scope.$watch(<data name goes here>, function(newVal) {
// update your LocalStorage now
});
Why it fails with ng-repeat?
The reason you see the behavior is quite simple. $scope.locationList2 is a single variable that gets bound for each member created by ng-repeat. That explains why it stays empty during edit.
You will need to bind the data using some other way. Consider binding it directly to your record models. Example: AngularJS - Using $index in ng-options .
Solution
The original code had bits like this:
JS:
$scope.editData = function (record) {
record.destination = $scope.location;
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="location" ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
Note that the markup is inside a ng-repeat and effectively each item created by it points at the same location! This isn't good.
To make it work I changed it like this:
JS:
$scope.editData = function () {
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="record.destination" ng-options="location.place as location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
As mentioned above the JS could be replaced by a watcher. The important thing to note here is that I bind the data directly to the records. That avoid hassle at editData and more importantly gets rid of the problematic ng-model reference.

jQuery show and hide dynamic classes not working

I am trying to hide and show div's displayed on my page with a select element however having a bit of trouble as I can't seem to get the jQuery to function.
I am listing results from my SQL table using PHP that currently displays every row onto my page and prints them into a list.
I want to make the jQuery hide the div's that don't have a class that matches the select option that is selected.
Here is an example of the listing template that echo's out all of the MySQL results and displays them into a template and is then looped to display every row on the table:
<?php while($row = $results->fetch(PDO::FETCH_ASSOC))
{
echo '
<div class="listing-container ' . $row["Make"] . '">
<h3 class="model-listing-title clearfix">'.$row["Make"].' '.$row["Model"].' '.$row["Variant"].'</h3>
<h3 class="price-listing">£'.number_format($row['Price']).'</h3>
</div>
<div class="listing-container-spec">
<img src="'.(explode(',', $row["PictureRefs"])[0]).'" class="stock-img-finder"/>
<div class="ul-listing-container">
<ul class="overwrite-btstrp-ul">
<li class="diesel-svg list-svg">'.$row["FuelType"].'</li>
<li class="saloon-svg list-svg">'.$row["Bodytype"].'</li>
<li class="gear-svg list-svg">'.$row["Transmission"].'</li>
<li class="color-svg list-svg">'.$row["Colour"].'</li>
</ul>
</div>
<ul class="overwrite-btstrp-ul other-specs-ul h4-style">
<li>Mileage: '.number_format($row["Mileage"]).'</li>
<li>Engine size: '.$row["EngineSize"].'cc</li>
</ul>
<button href="#" class="btn h4-style checked-btn hover-listing-btn"><span class="glyphicon glyphicon-ok"></span> History checked
</button>
<button href="#" class="btn h4-style more-details-btn hover-listing-btn tst-mre-btn"><span class="glyphicon glyphicon-list"></span> More details
</button>
<button href="#" class="btn h4-style test-drive-btn hover-listing-btn tst-mre-btn"><span class="test-drive-glyph"></span> Test drive
</button>
<h4 class="h4-style listing-photos-count"><span class="glyphicon glyphicon-camera"></span> 5 More photos</h4>
</div>
';
} ?>
The 'Make' is added to the listing-container div to add a class to be able to filter the results with jQuery.
Here is the form with the select element I am using:
<form>
<select class="form-control select-box">
<option value="make-any">Make (Any)</option>
<?php while($make = $filterres->fetch(PDO::FETCH_ASSOC))
{
echo '
<option>'.$make["Make"].'</option>
';
} ?>
</select>
<select class="form-control last-select select-box">
<option value="model-any">Model (Any)</option>
<option value="two">Two</option>
<option value="three">Three</option>
<option value="four">Four</option>
<option value="five">Five</option>
</select>
</form>
As you can see the select option contains the 'Make' and is looped.
So down to the jQuery:
<script>//Wait for DOM to load
(function() {
$(“.select-box”).change( function() {
// get the value of the select element
var make = $(this).val();
//get all of the listing-container divs, remove the ones with the selected make class, then hide the rest
$(“.listing-container”).not(“.” + make).hide();
});
});</script>
So in theory this should work but for some reason it isn't, can anybody notice anything that might be wrong?
I have placed my script below the core jQuery in my footer and it still doesn't work.
Here is a live example: http://www.drivencarsales.co.uk/used-cars.php
Looks like you're using the wrong quotes in the source code of that page try replacing them with "
//Wait for DOM to load
$(function() {
$(".select-box").change( function() {
// get the value of the select element
var make = $(this).val();
//get all of the listing-container divs, remove the ones with the selected make class, then hide the rest
$(".listing-container").not("." + make).hide().next().hide();
});
});
Edit
You also need a $ before the function
If I understand you correctly ↓ working code ↓
$(function() {
$('.select-box').on("change",function() {
var make = this.value;
$('div.listing-container.'+make+",div.listing-container."+make+" + div.listing-container-spec").show();
$('div.listing-container:not(.'+make+'),div.listing-container:not(.'+make+') + div.listing-container-spec').hide();
});
});
And shorter code (but slower):
$(function() {
$('.select-box').on("change",function() {
var make = this.value;
$('.listing-container.'+make+",.listing-container."+make+" + div").show();
$('.listing-container:not(.'+make+'),.listing-container:not(.'+make+') + div').hide();
});
});
P.S.You miss value attribute (but in live example everything ok):
echo '<option value="'.$make["Make"].'">'.$make["Make"].'</option>';

Hide element after this select box by change

I am working on a time table where users can update their opening hours.
I have select boxes per day with 'open' or 'closed', and after this time select boxes with 'from' and 'till'.
I want to make it so if a user select for example wednesday: 'closed', the till and from select boxes (list items in this .time_row) are hiding.
My HTML for each day:
<div class="time_row">
<label>Monday:</label>
<li>
<select>
<option value="open">Open</option>
<option value="closed">Closed</option>
</select>
</li>
<li>
From:
</li>
<li>
<select>
<option value="00:00">00:00</option>
<option value="01:00">01:00</option>
etc
</select>
</li>
<li>
Till:
</li>
<li>
<select>
<option value="00:00">00:00</option>
<option value="01:00">01:00</option>
etc
</select>
</li>
</div><!--End time_row-->
I have tried to make it with jQuery .slice() but then he hides all list elements after this select box and before?
// Account time table
$('.time_row select').change( function() {
if( $(this).val() == 'closed' ) {
$('.time_row li').slice(3).hide();
}
});
Can someone help me with this?
Thank you!
I assume you are looking for something like that:
$('.time_row').find('select:first').change(function() {
$(this)
.closest('.time_row')
.find('li')
.slice(1)
.toggle(this.value === 'open');
}).change();
In this case on change event you search for the <select> closest parent element with class .time_row. Then pick up all inner <li> elements, remove the first from the list with slice(1) and either show or hide the rest upon the condition this.value === 'open'.
You should also check your markup and put all <li> elements inside <ul> to make it valid.
In the updated answer I have included the correct selector to select only first <select> elements (ignoring time selectors) and added the by default state with triggering change event after binding.
DEMO: http://jsfiddle.net/mPNCA/1/
You can do (untested):
$(".time_row select:first").change(function() {
if (this.value == "closed") {
$(this).closest(".time_row").find("select").not(this).hide();
}
});

Problem with Sys.UI.DataView and javascript

I'm using Microsoft Ajax to dynamically populate a list of contacts, given a json packet. My code is as follows:
function fillContactsFromData(contacts) {
// this is just for debug to let me know that the data is correct
if (contacts.length > 0) {
alert('ID: ' + contacts[0].ID + ', Name: ' + contacts[0].Name);
}
$create(Sys.UI.DataView, { data: contacts }, null, null, $get('contacts'));
}
The associated html is as follows:
<div id="contacts" class="sys-template">
<a onclick="removeContact('{{ ID }}');"><img src="remove.png" /></a>
<a class="contact" rel="/Contacts/Index/{{ ID }}">{{ Name }}</a><br />
</div>
The first <a> tag is used to fire a script to remove the contact, while the second uses the jQuery cluetip to bring up a box on hover (details skipped here).
The problem I am having is that the HTML is not being rendered correctly. What is being generated is:
<div id="contacts">
<a><img src="remove.png" /></a>
<a class="contact" rel="/Contacts/Index/{{ ID }}">Darren Oster</a><br />
</div>
The alert box indicates data with valid ID (a Guid) and Name ("Darren Oster"). The Name is being rendered correctly, but the ID field is not rendered in the 'rel' attribute, and the 'onclick' statement is removed entirely.
Is this a limitation of MS Ajax or am I doing something incorrectly?
Thanks in advance.
If an attribute is to contain any {{ }} expressions it must be the entire value.
Yes:
foo="{{ 'abc' + ID }}"
No:
foo="abc{{ ID }}"
As for onclick not being generated, it probably is, but whatever inspection you are using doesn't show you the value, since it is set with a direct set of element.onclick, not addAttribute().
InfinitiesLoop put me on the right track, so here's the final answer (in case anyone else follows this path)...
First, I was using an earlier preview of MS Ajax 4.0. I've now updated to preview 5, and things work slightly differently. Here's the final HTML (the javascript is unchanged):
<div id="contacts" class="sys-template">
<a sys:onclick="{{ 'removeContact(\'' + ID + '\');' }}"><img src="remove.png" /></a>
<a class="contact" sys:rel="{{ '/Contacts/Index/' + ID }}">{{ Name }}</a><br />
</div>
Also note that preview 5 requires the 'sys:' prefix on any attributes that have data-bound values, so
<option value="{{ Value }}">{{ Text }}</option>
inside a <select> becomes
<option sys:value="{{ Value }}">{{ Text }}</option>

Categories

Resources