I have this mini app that allows the user to enter the make and model of a car, then adds it to the table below. I have added a function that will check for duplicates and alert if there are any already existing in the table. If there are no existing records that match, it will push the new "make" and "model" to the table. I changed the code to use _.isEqual instead of what I had prior and now it gets caught at the Alert every time I run it. Anyone know what is going on?
<div>Make: <input type="text" ng-model="make"></div>
<div>Model:<input type="text" ng-model="model"></div>
<button ng-click="add()">Add</button>
<tr>
<th>Make</th>
<th>Model</th>
</tr>
<tr ng-repeat="car in cars" ng-click="rowClick(car)">
<td>{{car.make}}</td>
<td>{{car.model}}</td>
</tr>
var carsApp = angular.module('carsApp', []);
carsApp.controller('carController', function ($scope){
$scope.cars = [];
$scope.add = function () {
var newCar = {
make: $scope.make,
model: $scope.model
};
function hasDuplicates(){
angular.forEach($scope.cars, function(car, key){
_.isEqual(car, newCar);
});
}
if (hasDuplicates) {
alert("Car already exists");
} else {
$scope.cars.push(newCar);
}
}
$scope.rowClick = function(car){
$scope.make= car.make;
$scope.model= car.model;
};
$scope.make = null;
$scope.model = null;
});
Ended up going with a simpler option and used angular.equals instead. isEqual was too much of a pain to implement properly. Thanks for all the help!
function hasDuplicates(newCar){
var returnVal = false;
angular.forEach($scope.cars, function(car, key){
if (angular.equals(car, newCar))
{
returnVal = true;
}
});
return returnVal;
};
Related
I'm at my wits end! In angular I've got a controller and a view.
There are 2 dropdowns on the page which need to reset to default once the restart button has been clicked.
I can set the value of the boxes as they render by pushing a "select" option into the collection inside the controller. However, when the reset button is pressed, which runs the init() method again, the dropdowns should be set back to the first value. This doesn't occur, the values for $scope.selectedYear and $scope.selectedReport remain as they did before the reset button was pressed.
This is the full code for the controller
function TreeReportsCHLController($scope, $q, $routeParams, reportsDashboardResource, navigationService, notificationsService, dialogService, entriesManageDashboardResource, $timeout) {
// Methods
var generalError = function () {
notificationsService.error("Ooops", "There was an error fetching the data");
$scope.actionInProgress = false;
}
// Scope
$scope.selectedYear = "";
$scope.init = function () {
$scope.hasCompleted = false;
$scope.actionInProgress = false;
$scope.yearSelected = false;
$scope.reportTypes = ["Choose", "Entered", "ShortListed", "Winner", "Recieved"];
$scope.selectedReport = "";
$scope.entryYears = new Array();
$scope.entryYears.push("Choose a Year");
entriesManageDashboardResource.getEntryYears().then(function (response) {
angular.forEach(response, function (value, key) {
$scope.entryYears.push(value);
});
});
$scope.selectedYear = $scope.entryYears[0];
$scope.selectedReport = $scope.reportTypes[0];
};
$scope.yearHasSelected = function(selectedYear) {
$scope.yearSelected = true;
$scope.selectedYear = selectedYear;
};
$scope.generateFile = function (selectedReport) {
$scope.actionInProgress = true;
var reportDetail = {
entryYear: $scope.selectedYear,
chosenEntryStatus: selectedReport
};
reportsDashboardResource.generateEntriesReportDownloadLink(reportDetail).then(function (response) {
if (response.Successful) {
$scope.hasCompleted = true;
} else {
notificationsService.error("Ooops", response.ErrorMessage);
}
$scope.actionInProgress = false;
}, generalError);
};
$scope.restart = function () {
$scope.init();
}
// Initialise Page
$scope.init();
}
angular.module("umbraco").controller("ReportsDashboardController", TreeReportsCHLController)
this is the code with the dropdowns in it;
<table>
<tr>
<td>Get a report for year: {{selectedYear}}</td>
<td><select ng-model="selectedYear" ng-change="yearHasSelected(selectedYear)" ng-options="year for year in entryYears" no-dirty-check></select></td>
</tr>
<tr ng-show="!hasCompleted && yearSelected">
<td>
Get Report Type:
</td>
<td>
<select ng-model="selectedReport" ng-change="generateFile(selectedReport)" ng-options="status for status in reportTypes" no-dirty-check ng-disabled="actionInProgress"></select>
</td>
</tr>
</table>
I've also done a further test where I simply set $scope.selectedYear to $scope.entryYears[0] within the reset method. When I console.log $scope.selectedYear here, the value confirms it has been changed, but strangely where I've outputted the $scope.selectedYear / {{selectedYear}} to the page for testing, this does not update. It's almost as though the binding between the controller and the view isn't occuring.
Any help?
Thank-you.
Here's a working plunk that is somewhat stripped down since I didn't have access to of the services that your are injecting into your controller. The changes I made in the controller are:
First,
$scope.entryYears = new Array();
becomes
$scope.entryYears = [];
as this is the preferred way to declare an array in js.
Second, I removed $scope.apply() that was wrapping
$scope.selectedYear = $scope.entryYears[0];
$scope.selectedReport = $scope.reportTypes[0];
as this was causing infinite digest cycles.
Two basic questions,
1) I have a controller where I define a list with a key, value structure and I want to access to the event name based on the eventID and log it in the console
$scope.events = [
{eventID:3200, eventName:"Event One"}
{eventID:3201, eventName:"Event Two"}
];
I tried this:
if($scope.events.eventID == 3200) {
console.log("Ok");
}
but it didnt worked :(
2) Then in my view I have a table where i print data coming from a WS, what I want is to print the description on the table depending on the eventID from my $scope.events list, I have a field on my ng-repeat named event that will let me compare with the eventID from the list but I dont know how to do this.
<tr ng repeat d in data>
<td>d.Description</td>
<td>d.anyValue</td>
</tr>
Any help is welcome, I really need it I'm new to Angular :)
Add method in controller
$scope.search=function(obj){
return obj.eventID === 3200;
}
add it to view
<tr ng-repeat="d in data | filter:search">
<td>d.Description</td>
<td>d.anyValue</td>
</tr>
for question number 1, try with this
if($scope.events[0].eventID == 3200) {
console.log("Ok");
}
for looping using this
angular.forEach($scope.events, function (value) {
if (value.eventId === 3200) {
{
console.log('OK');
}
});
for question number 2, create helper function to return eventName base on the ID.
$scope.getEventName = function (eventId) {
var result = '';
angular.forEach($scope.events, function (value) {
if (value.eventID === eventId) {
result = value.eventName;
return false;
}
});
return result;
}
<tr ng-repeat="d in (exportDataEventDesc.result.slice(5, exportDataEventDesc.result.length-2))">
<td>{{d.Description}}</td>
<td>{{d.anyValue}}</td>
<td ng-bind="getEventName(d.merchMetrics.EVENT_ID)" style="text-align: left"></td>
</tr>
I have a simple form with a checkbox which clicked deletes a property from an object.
Here is the controller:
app.controller('PropController', function ($scope) {
var str = '{"meta":{"aprop":"lprop"},"props":{"gprop":12,"lprop":9,"wrop":5}}';
$scope.filecontent = JSON.parse(str);
$scope.delprop = false;
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('delprop', function () {
if ($scope.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
And the view:
<div ng-app="SomeProperties" ng-controller="PropController">
<div ng-if="proptodel">
there is a property to delete: {{proptodel}}
<form><input type="checkbox" ng-model="delprop"></form>
filecontent: {{filecontent}}
</div>
<div ng-if="!proptodel">
there is NO property to delete
</div>
</div>
The app on jsfiddle.
The problem appears when the form is in the ng-if, it stops behaving. As you can try it in the jsfiddle, when I delete ng-if="proptodel" from the div containing the form, it working normally. What is the explanation of this?
You need to put the delprop into in object to make ng-model work properly. That means your markup should have:
<form><input type="checkbox" ng-model="obj.delprop"></form>
And your Javascript code should look like:
$scope.obj = {
delprop: false
};
$scope.propobj = $scope.filecontent.props;
$scope.proptodel = $scope.filecontent.meta.prop;
var mainvalue = $scope.propobj[$scope.proptodel];
$scope.$watch('obj.delprop', function () {
if ($scope.obj.delprop == true) {
delete $scope.propobj[$scope.proptodel];
} else {
$scope.propobj[$scope.proptodel] = mainvalue;
}
});
Of course you should find a proper name for the object as obj is really bad and generic ;-)
I've a list on ng-repeat that displays a list of results from a $http query (bind to an input). I'd like both for the list to disappear when the user clicks on one of the results and for the initial empty value of the model to be restored.
Basically, the functionality is as follows:
User searches term, list displays results, user clicks on result, list disappears, user clicks on input again to make another search, list with new results appear.
So far I've managed to make the list disappear, but not to make it appear again when the user makes another search.
Here's the relevant code:
<input type="text" ng-model="name" ng-click="Research()"/>
<ul ng-hide="clicked" ng-show="retype">
<li ng-repeat="result in results" ng-click="getDetails(result.id)">{{result.title}}</li>
</ul>
And the JS:
function Ctrl($scope, $http) {
var get_results = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=8').
success(function(data3) {
$scope.results = data3.results;
});
}
}
$scope.name = '';
$scope.$watch('name', get_results, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=500').
success(function(data2) {
$scope.releases = data2.releases;
});
$scope.clicked = true;
}
function Research(){
$scope.retype = true,
$scope.name = '';
}
Plunkr is down, I'll make one as soon as possible. Any idea about what am I missing?
I tidied up your code a little bit. Please note that the div is shown only when artist is defined. So when it is set to undefined by the $scope.clear() method, the mentioned div is hidden.
Html part:
<div ng-controller="Ctrl">
<input type="text" ng-model="name" ng-focus="clear()"/>
<ul>
<li ng-repeat="result in results" ng-click="getDetails(result.id)">{{result.title}}</li>
</ul>
<div ng-show="artist">
<h1>Artist</h1>
<ul>
<li>{{artist.name}}</li>
<li>{{artist.release_url}}</li>
<li>{{artist.uri}}</li>
<li>{{artist.resource_url}}</li>
</ul>
</div>
</div>
JavaScript part:
var myApp = angular.module('myApp',[]);
function Ctrl($scope, $http) {
$scope.name = undefined;
$scope.artist = undefined;
$scope.results = undefined;
var search = function (name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=8').
success(function(data3) {
$scope.results = data3.results;
});
}
}
$scope.$watch('name', search, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=500').
success(function(data2) {
$scope.releases = data2.releases;
});
}
$scope.clear = function () {
$scope.name = undefined;
$scope.artist = undefined;
$scope.results = undefined;
}
}
There is working JSFiddle.
Your Research function is unnecessary because you don't need ng-show and ng-hide same time...
secondly you set clicked to ok but never set it false again after your research done...
here is working PLUNKER
Try using just one ng-hide or ng-show, instead of both. Since you never set clicked back to false, it is probably overriding the retype.
Both functions are two-way, so you can just use ng-hide="clicked", and inside function Research, set $scope.clicked to false.
I'm trying to bind a 1-many mapping using KnockoutJS, where 1 zip code can have many 'agents'. I have the following classes:
function CaseAssignmentZipCode(zipcode, agent) {
var self = this;
self.zipcode = ko.observable(zipcode);
self.agent = ko.observable(agent);
}
function Agent(id, name) {
var self = this;
self.id = id;
self.name = name;
}
function ZipcodeAgentsViewModel() {
var self = this;
self.caseAssignmentZipCodes = ko.observableArray([]);
self.agents = ko.observableArray([]);
jdata = $.parseJSON($('#Agents').val());
var mappedAgents = $.map(jdata, function (a) { return new Agent(a.Id, a.Name) });
self.agents(mappedAgents);
var dictAgents = {};
$.each(mappedAgents, function (index, element) {
dictAgents[element.id] = element;
});
var jdata = $.parseJSON($('#CaseAssignmentZipCodes').val());
var mappedZipcodeAgents = $.map(jdata, function (za) { return new CaseAssignmentZipCode(za.ZipCode, dictAgents[za.UserId], false) });
self.caseAssignmentZipCodes(mappedZipcodeAgents);
}
var vm = new ZipcodeAgentsViewModel()
ko.applyBindings(vm);
My bindings look like this:
<table>
<thead><tr><th>Zipcode Agents</th></tr></thead>
<tbody data-bind="foreach: caseAssignmentZipCodes">
<tr>
<td><input data-bind="value: zipcode"></td>
<td><select data-bind="options: $root.agents, value: agent, optionsText: 'name'"></select></td>
<td>Remove</td>
</tr>
</tbody>
</table>
Everything binds fine the first time, with the table and select fields appearing properly. However, nothing happens when I change the selected value on any of the select elements. I have bound other elements to them and these don't update, and I've tried using .subscribe() to listen for the update event, but this doesn't fire either.
I expect there's something wrong with the way I'm setting up/binding these relationships, but I can't figure it out to save my life.
Thanks!
I think you need to add
self.agents = ko.observableArray([]);
at the top of ZipcodeUsersViewModel