Why is my AngularJs 'add' button only working once? - javascript

I'm just starting out with Angular.
I've written some code that downloads a JSON array configuredAPIs and displays each object within it, <div ng-repeat="capi in configuredAPIs">. For each of these, there's another directive to list the items from an array of strings, <tr ng-repeat="eurl in capi.externalURLs">
Underneath there's a text box to add a new string to this array, which I've bound to a $scope variable called url.
When I click the 'add' button, everything works - the new string is added to the array, a new row appears in the table.. ..but it only works once. Subsequent clicks on the 'add' button add empty strings to the array (and thus empty text boxes).
What have I done wrong?
index.html
<div ng-app="testApp" ng-controller="testCtrl">
<div ng-repeat="capi in configuredAPIs">
<h1>Configured API</h1>
<p>
Name:
{{ capi.name }}
</p>
<h2>External URLs</h2>
<form ng-submit="addExternalURL(capi)">
<table>
<!-- A row in the table for each string in the array -->
<tr ng-repeat="eurl in capi.externalURLs">
<td>
<input type="text" ng-model="eurl" />
</td>
</tr>
<!-- Final table row to add a new string to the array -->
<tr>
<td>
<input type="text" ng-model="url" placeholder="Enter a new external URL">
<input class="btn-primary" type="submit" value="add">
</td>
</tr>
</table>
</form>
</div>
</div>
controller.js
var app = angular.module('testApp', []);
app.controller('testCtrl', function ($scope, $http) {
$scope.url = 'new url';
$http.get("/api/configuredapis?orgid=2")
.success(function (response) { $scope.configuredAPIs = response; });
$scope.addExternalURL = function ($capi) {
$capi.externalURLs.push($scope.url);
$scope.url = '';
};
});

It is because AngularJS does not watch and update primitives (e.g. strings, numbers, booleans) the way one obviously thinks it does.
So instead you bind objects with values to the scope or use a function which returns the primitive value.
See:
https://github.com/angular/angular.js/wiki/Understanding-Scopes
http://www.codelord.net/2014/05/10/understanding-angulars-magic-dont-bind-to-primitives/
Example for using an object (at controller):
$scope.primitives = {
url : 'foo://'
}
And within the template:
<input type="text" ng-model="primitives.url">
So what happens in your example is that once you set it to '' the changes to the model within the template are not recognized anymore.

Related

how to get ng-repeat checkbox values on submit function in angularjs

I have a form which has 10 checkboxes. By default angular js triggers on individual checkbox. I want to grab all selected check box values on submit action only. Here is my code...
<form name="thisform" novalidate data-ng-submit="booking()">
<div ng-repeat="item in items" class="standard" flex="50">
<label>
<input type="checkbox" ng-model="typeValues[item._id]" value="{{item._id}}"/>
{{ item.Service_Categories}}
</label>
</div>
<input type="submit" name="submit" value="submit"/>
</form>
$scope.check= function() {
//console.log("a");
$http.get('XYZ.com').success(function(data, status,response) {
$scope.items=data;
});
$scope.booking=function(){
$scope.typeValues = [];
console.log($scope.typeValues);
}
I am getting empty array.
Can somebody tell how to grab all selected checkbox values only on submit event.
<div ng-repeat="item in items">
<input type="checkbox" ng-model="item.SELECTED" ng-true-value="Y" ng-false-value="N"/>
</div>
<input type="submit" name="submit" value="submit" ng-click="check(items)"/>
$scope.check= function(data) {
var arr = [];
for(var i in data){
if(data[i].SELECTED=='Y'){
arr.push(data[i].id);
}
}
console.log(arr);
// Do more stuffs here
}
Can I suggest reading the answer I posted yesterday to a similar StackOverflow question..
AngularJS with checkboxes
This displayed a few checkboxes, then bound them to an array, so we would always know which of the boxes were currently checked.
And yes, you could ignore the contents of this bound variable until the submit button was pressed, if you wanted to.
As per your code all the checkboxes values will be available in the typeValues array. You can use something like this in your submit function:
$scope.typeValues
If you want to access the value of 3rd checkbox then you need to do this:
var third = $scope.typeValues[2];
Declare your ng-model as array in controller, like
$scope.typeValues = [];
And in your template, please use
ng-model="typeValues[item._id]"
And in your controller, you will get this model array values in terms of 0 and 1. You can iterate over there.

Angular js get div element issue

I am trying to get a div element value by ng-click but it comes an alert undefined.
my html is
<div ng-model='myName'>this is my name</div>
<br/>
<input type="button" value="Show Name" ng-click="showName()"/>
script is
$scope.showName = function(){
var nameOne = $scope.myName;
alert(nameOne);
}
How to solve this issue. Thank you.
ngModel directive can't be used with plain div (unless the element is a custom form control), see https://docs.angularjs.org/api/ng/directive/ngModel
<div ng-init="myName = 'this is my name'">{{ myName }}</div>
<br/>
<input type="button" value="Show Name" ng-click="showName()"/>
Plunker here
Edit: using ngInit outside of ngRepeat is considered a bad practice, initialize scope vars in the controller
$scope.myName = 'this is my name';
$scope.showName = function() {
alert($scope.myName);
}
<div>{{myName}}</div>
<br/>
<input type="button" value="Show Name" ng-click="showName()"/>
script is
$scope.showName = function(){
var nameOne = $scope.myName;
alert(nameOne);
}
Actually ng-model should be use on inputs.
<input type="text" ng-model="myName">
This Will create a $scope.myName var and bind it to the input content.
If you intitialize the myName in your javascript and want it to be displayed in this div you should use this syntax :
JS
$scope.myName = "Ben";
HTML
<div>This is my name : {{myName}}</div>
In both case your button click will not show undefined unless you didn't initialize it before the click (on the 2nd exemple).
Hope it helped.

ng-repeat scope issue: two level inheritance?

I got an array of objects, these objects having properties.
I want to be able modify the properties of one of these objects thanks to a ng-repeat -> and that the changes I make are also done in the original array
I've tried to properly do format my array so that the inheritance is ok: when I change in the ng-repeat it changes in the $scope. But it doesn't go to the original array.
I don't know how I could change my data/arrays in order to make it work.
What should I do ? How can I transform my data ?
here is a fiddle that shows all this
ps: I've tried using the parent scope but as you can see in my example I don't even success in that :( anyway it's advised to avoid it if possible
and here's the JS code:
var myApp = angular.module('myApp',[]);
myApp.controller('myController', function ($scope) {
//source array
var origine = [
{id:"1",name:"elem1"},
{id:"2",name:"elem2"},
{id:"3",name:"elem3"} ];
//what I am doing now
$scope.element = origine[1];
//i'd like to transform the array so that I have inheritance and I can avoid using parent scope
var reference = [];
var i =0;
for (var key in origine[2]) {
if (origine[1].hasOwnProperty(key)) {
reference[i] = {prop:origine[2][key]};
i++;
}
}
$scope.element2 = reference;
$scope.element3 = origine[0];
$scope.check = function()
{
//to check if the source array is modified
console.log(origine);
}
});
and here HTML:
<div ng-app="myApp">
<div ng-controller="myController">
--------------- BASIC example -----------------
<br/> Repeat scope
<div ng-repeat="property in element">
<input ng-model="property"/>
</div>
<br/>"Parent"
<input ng-model="element.name"/>
<br/><input type="button" ng-click="check()" value="check origine"/>
<br/><br/>--------------- Trying inheritance -----------------
<br/> Repeat scope
<div ng-repeat="property in element2">
<input ng-model="property.prop"/>
</div>
<br/> "Parent"
<input ng-model="element2[1].prop"/>
<br/><input type="button" ng-click="check()" value="check origine"/>
<br/><br/>--------------- Trying parent scope -----------------
<br/> Repeat scope
<div ng-repeat="property in element3">
<input ng-model="$parent.property"/>
</div>
<br/> "Parent"
<input ng-model="element3.name"/>
<br/><input type="button" ng-click="check()" value="check origine"/>
</div>
</div>
Thats because the variable is being assigned by reference.
Try assigning the array directly to the scope and manipulate that array, or create a scope method to push, splice, update that private array
If I understand you question correctly you can refer to property by key to get it updated:
<div ng-repeat="(key, property) in element">
<input ng-model="element[key]"/>
</div>
Fiddle: http://jsfiddle.net/xezbs8gn/7/

Make AngularJS page double as search results page

I have a basic table in which I'm displaying data, as pulled from a database, through AngularJS. I also have a search field that uses AngularJS to filter the data:
<input ng-model="search" id="search" type="text" placeholder="Search" value="">
<div ng-controller="eventsController")>
<table>
<tr ng-repeat="event in events | filter:search">
<td><span ng-bind="event.title"></span></td>
<td><span ng-bind="event.date_start"></span></td>
</tr>
</table>
</div>
<script>
function EventsController($scope, $http) {
$http.get('/api/all-events').success(function(events) {
$scope.events = events;
});
}
</script>
This is great for user-defined searches, but what if I want to run a particular filter upon page load while maintaining the search functionality? Is there a way that I can use AngularJS to automatically filter the results based on a URL parameter (i.e. example.com?search=foo)? Ideally, the value of the the input field would also be set to the URL parameter.
Like the comments said, this has nothing to do with filter. It's more about how you organize your code to customize URL path you send to the server. You can try to do it this way:
function EventsController($scope, $http) {
// this field is bound to ng-model="search" in your HTML
$scope.search = 'ALL';
$scope.fetchResults = function() {
var path;
if ($scope.search === 'ALL') {
path = '/api/all-events';
} else {
path = '/search?input=' + $scope.search;
}
// here we send different URL path
// depending on the condition of $scope.search
$http.get(path).success(function(events) {
$scope.events = events;
});
};
// this line will be called once when controller is initialized
$scope.fetchResults();
}
And your HTML code, make sure your controller is on the parent div of the input field and search button. And for the search button, you invoke fetchResults() when it's clicked:
<div ng-controller="eventsController")>
<input ng-model="search" id="search" type="text" placeholder="Search" value="">
<button ng-click="fetchResults()">Search</button>
<div>
<table>
<tr ng-repeat="event in events | filter:search">
<td><span ng-bind="event.title"></span></td>
<td><span ng-bind="event.date_start"></span></td>
</tr>
</table>
</div>
</div>

Angular: Push item to list doesn't update the view

When I push an item to an array, the view won't refresh the list.
table:
<tbody id="productRows">
<tr data-ng-repeat="product in products | filter: search">
<td>{{ product.Code}}</td>
<td colspan="8">{{ product.Name}}</td>
</tr>
</tbody>
form:
<form data-ng-submit="submitProduct()">
Code:
<br />
<input type="text" required data-ng-model="product.Code"/>
<br />
<br />
Naam:
<br />
<input type="text" required data-ng-model="product.Name"/>
<br />
<input type="submit" value="Opslaan" />
</form>
submitProduct in controller:
$scope.submitProduct = function () {
console.log('before: ' + $scope.products.length);
$scope.products.push({Code: $scope.product.Code, Name: $scope.product.Name});
console.log('after:' + $scope.products.length);
console.log($scope.products);
$scope.showOverlay = false;
};
As you can see, I log the total items in the array and it behaves like I would expect. The only thing that doesn't do what I expect is the content of my table, that doesn't show the new value.
What do I have to do, so the new row is displayed in the table?
I can't see the rest of your code, but make sure $scope.products is defined in your controller.
See this example.
The only addition I made to the code you provided was:
$scope.products = [];
If this doesn't help then please provide more information.
Thanks for the answer and the comments. The problem was at another place. In my routeProvider I had declared a controller. I also had a ng-controller directive in my div. So my controller gets executed twice. When I removed the ng-controller directive, everything was just working as it should be :)

Categories

Resources