angular.js Table Filtering - angularjs

I was trying to create a table with a filter at the top of each column.
I am unable to figure out why the Any filter is working but not the individual colum filters.
I have the code # http://plnkr.co/edit/6ghH02
I have also tried to compile the element after setting the ng-model but it did not work.
Can anyone please help?

You can do this if you get rid of the directive and use the ng-change attribute of the input[text] like so:
function TestController ($scope) {
$scope.valueChanged = function (name, value) {
if (!$scope.search) {
$scope.search = {};
}
$scope.search[name] = value;
}
};
<body ng-controller="TestController">
<th ng-repeat="sortName in columnNames">
<input type=text ng-model="value" ng-change="valueChanged(sortName, value)">
</th>
The short version of the answer as to why your original code doesn't work is that ngRepeat creates a new scope and the value in ng-model must be an assignable variable.

As #Ryan pointed out, ng-repeat's nested scopes are the trick. An alternative to writing a controller method is to use the $parent property of the child scope to access the search property in the parent scope:
<th ng-repeat="sortName in columnNames">
<input type=text ng-model="$parent.search[sortName]"></th>
As in #Ryan's solution, a directive is not needed.
However, the additional search properties needed to be created/initialized:
<div ng-init="search.name = ''; search.phone = ''"></div>
http://plnkr.co/edit/wT34vh?p=preview

Related

How to set value from controller to Input Box using "this" operator

I am newbie to angular js. I got the data successfully from php but calling it from the controller, it's not working? I don't get any errors, my syntax is just wrong.
For eg: Suppose, A in entered in input box then On click event, B should be displayed in another text box.
If P is entered, then On click event, Q should be displayed and so on.
I am adding the text box using dynamically added rows. On each Click, data should be displayed.
HTML:
<tr ng-repeat="bot in bottles">
<td><input type="text" ng-model="bot.b_code" /></td>
<td><input type="text" ng-click="accept1()" ng-model="bot.Pre_req" /></td>
</tr>
<td><a href ng-click="remove_bottle(bottle)">Remove</a></td>
</tr>
<tr><td><a href ng-click="add_bottle()">Add</a></td></tr>
Controller:
$scope.accept1=function(){
$http.get("machin.php", {params:{"W_id": this.bot.b_code}})
.success(function(response){
this.bot.Pre_req=response;
});
};
machin.php
if($W_id=='A')
echo 'B'
else($W_id==P)
echo 'Q'
I unable to find the solution.Please do suggest.Thanks in advance.
Try adding bot to $scope instead of this
$scope.accept1=function(){
$scope.bot = {};
$http.get("machin.php", {params:{"W_id": this.bot.b_code}})
.success(function(response){
$scope.bot.Pre_req=response;
});
};
In this case this would refer not even to scope of accept1 function but to scope of anonymous function in success callback, so that's why it won't work as is. You can confirm this by trying to console.log(this.bot) in the end of accept1 function. It will be undefined
Since you use $scope way to implement things, So I suggest to completely remove this from your controller code, since it doesn't attach anything on view.
and, make below changes :
1.Define both ng-model objects in your controller, like :
$scope.bot = {b_code:'', Pre_req : ''};
2.Change your function call with correct binding to $scope, like :
$scope.accept1=function(){
var scope = $scope;
$http.get("machin.php", {params:{"W_id": scope.bot.b_code}})
.success(function(response){
scope.bot.Pre_req=response;
});
};
also, change .success to .then, as it is depreciated.
3.I think you also need to change the ng-click target to upper input., as you are changing the below input. Code should be like:
<td><input type="text" ng-click="accept1()" ng-model="bot.b_code" /></td>
<td><input type="text" ng-model="bot.Pre_req" /></td>
Second Approach:, If you want to use this keywaord then I suggest having a read for this syntax.. Basically you have an alias for your controller in both html and JS, and this represent the controller alias in JS. (so you get rid of $scope)

Directive with ng-model Attribute Not Resolving Using $http

Trying to make a rating directive but I'm stuck at getting rating2 to work. The first rating worked because the rating1 is hardcoded within the controller. But normally I have to get the saved rating from the db, which I'm trying to do with rating2, as u can see the value is fetched but the directive is not appearing.
https://codepen.io/eldyvoon/pen/MbBNLP
<div star-rating ng-model="rating.rating1" max="10" on-rating-select="rating.rateFunction(rating)"></div>
<br>but rating2 is actually there:
{{rating.rating2}}
<star-rating ng-model="rating.rating2" readonly="rating.isReadonly"></star-rating>
Need expert of directive to help.
Initiate rating2 :
function RatingController($http) {
this.rating1 = 5;
this.rating2 = 0; //ADD THIS LINE
var self = this;
it works for me
check here
First of all, I'm not a directive expert but i'm trying to help. I think that when html is first load, the values from db not finish execute and bind into html. The best way is not using directive instead using controller to fetch data from db.
You pass a model without rating2 into your directive and the changes from the parent controller won't affect it, because variable is created afterwards. Adding a watcher in your linker on parent scope will solve the problem;
scope.$parent.$watch('', function(rating){
updateStars();
});
Other solution would be to define a starting value in your controller.
this.rating2 = 1;
Notice that it is bad design to have a scope variable for each rating. It is cleaner to have an array of ratings and you actually do not need the watcher by doing so.
https://codepen.io/hoschnok/pen/LbJPqL
angular controller
function RatingController($http) {
this.ratings = [4];
var self = this;
$http.get('https://api.myjson.com/bins/o0r69').then(function(res){
self.ratings.push(res.data.rating2);
});
}
HTML
<div ng-app="app" ng-controller="RatingController as rating" class="container">
<div ng-repeat="r in rating.ratings">
<div star-rating ng-model="r" max="10" on-rating-select="rating.rateFunction(rating)"></div>
</div>
</div>
The watcher change handler function has parameters reversed:
//INCORRECT parameters
//scope.$watch('ratingValue', function(oldValue, newValue) {
//CORRECT parameters
scope.$watch('ratingValue', function(newValue, oldValue) {
if (newValue) {
updateStars();
}
});
The first argument of the listening function should be newValue.
The DEMO on CodePen
ALSO
The ng- prefix is reserved for core directives. See AngularJS Wiki -- Best Practices
JS
scope: {
//Avoid using ng- prefix
//ratingValue: '=ngModel',
ratingValue: '=myModel',
max: '=?', // optional (default is 5)
onRatingSelect: '&?',
readonly: '=?'
},
HTML
<!-- AVOID using the ng- prefix
<star-rating ng-if='rating' ng-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
-->
<!-- INSTEAD -->
<star-rating ng-if='rating' my-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
When a custom directve uses the name ng-model for an attribute, the AngularJS framework instantiates an ngModelController. If the directive doesn't use the services of that controller, it is best not to instantiate it.

How to use a dynamically generated value in a template in AngularJS

I have a custom form application written in AngularJS and now I need to use the data from the form in a template. But nothing I've tried seems to work.
I am creating a custom directive like this...
.directive('dynamicModel', ['$compile', function ($compile) {
return {
'link': function(scope, element, attrs) {
scope.$watch(attrs.dynamicModel, function(dynamicModel) {
if (attrs.ngModel == dynamicModel || !dynamicModel) return;
element.attr('ng-model', dynamicModel);
if (dynamicModel == '') {
element.removeAttr('ng-model');
}
// Unbind all previous event handlers, this is
// necessary to remove previously linked models.
element.unbind();
$compile(element)(scope);
});
}
};
}])
This is attached to a form element like this..
<div class="row" ng-repeat="field in customForm.fields">
<label>{{field.displayname}}
<input class="form-control" type="{{field.type}}" name={{field.variable}} dynamic-model="field.databind" placeholder="{{field.variable}}" required="{{field.isRequired}}"></label></div>
This part works great, the field is now 2 way bound to the input form.
However when I later tried to use the same method to show the value in a report computed from the form, I get "field.databind" or at best the resolved databind field name such as "currentUser.name" rather than the value, e.g. "devlux"
I've tried
<div class="row" ng-repeat="field in customForm.fields">
<p>{{field.name}} = {{field.databind}}</p>
Also
<p dynamicModel="field.databind"></p>
</div>
Nothing works unless I put it into an input element, which isn't what I'm trying to do here.
The dynamic model code was pulled off someone elses answer to a question about creating dynamic form elements, and honestly I think it's just a step beyond my comprehension. But assuming that "field.databind" will always be a string literal containing the name of an inscope model, how on earth do I access it in a normal template?
{{field.databind}} will be evaluated against the current $scope and will result in whatever $scope.field.databind is, for example the string currentUser.name.
Angular has no way of knowing that currentUser.name isn't the string you want, but actually another expression that you want to evaluate.
To evaulate it again you will need to add a function to your $scope that uses the $parse service.
For example:
$scope.parseValue = function (value) {
return $parse(value)($scope);
};
In HTML:
<div class="row" ng-repeat="field in customForm.fields">
<p>{{field.displayname}} = {{parseValue(field.databind)}}</p>
</div>
The argument that gets passed to parseDynamicValue will for example be currentUser.name. Then it uses the $parse service to evaulate the expression against the current $scope, which will result in for example devlux.
Demo: http://plnkr.co/edit/iPsGvfqU0FSgQWGwi21W?p=preview

How can I use Variable expressions in AngularJS

In PHP I can use a double dollar sign to use a variable to represent another variable. If like to do the same in AngularJS expressions.
For example if I had an object with property1, property2 etc each with different values I would reference them directly as {{$scope.property1}}
What I would like to do is something like string propertyToDisplay = 'property1' and then use {{$scope.propertyToDisplay}} show the value stored in property1.
Does AngularJS support this?
This appears to be an XY problem. In general, the $scope variable shouldn't be appearing in your views at all, let alone that you seem to be trying to go outside the boundaries of what should be put in the markup for an AngularJS view.
In general, the parts of your controller that should appear in your view are (1) properties of the scope (or properties of properties, etc.) (2) functions that are part of the scope (with scope properties passed in as arguments). For anything involving dynamic functionality, you should generally be using the latter. So you could have your controller defined like this:
angular.module('myModule', [])
.controller('myController', ['$scope', function ($scope) {
$scope.properties = {
property1: "Hey!",
property2: "Hi"
};
$scope.selectedProperty = '';
$scope.getProperty = function (propertyName) {
return $scope.properties[propertyName];
};
}]);
And then your view could have something like this:
<select ng-model="selectedProperty">
<option value="property1">Property 1</option>
<option value="property2">Property 2</option>
</select>
<p>The value of the property you selected is: {{getProperty(selectedProperty)}}</p>
You can access variable object attribute using square brackets:
attrname ='attribute_name';
obj[attrname] = something;
How about using another object to store the visibility of each object property (DEMO).
$scope.visible = {};
$scope.person = {
first_name: 'John',
last_name: 'Rambo',
city: 'Hollywood'
};
Create a list with checkboxes for each property:
<div ng-repeat="(key, value) in person">
<input id="{{key}}Check" type="checkbox" ng-model="visible[key]">
<label for="{{key}}Check">{{key}}</label>
</div>
And check the visibility of each property in the form:
<input type="text" ng-model="person.first_name" ng-show="visible['first_name']">
If you want the form to be dynamic too (only input fields in this case) you can of course put this in a ng-repeat too:
<input ng-repeat="(key, value) in person" type="text" ng-model="person[key]" ng-show="visible[key]">
Hope this is at least close to what you want.

Preserving Scope in ng-repeat ( not wanting child scope )

I might be missing something conceptually but I understand that ng-repeat creates child scopes but for my scenario this is undesirable. Here is the scenario. I have a 3way bind to a firebase dataset. The object is an object with n sub objects. In my current code structure I use ng-repeat to iterate and render these objects with a custom directive. The issue is that these objects are meant to be "live" ( meaning that they are 3-way bound. The highest level object is bound with angularfire $bind ).
So the simple scenario in my case would be where the ng-repeat created scope was not isolated from the scope that it was created from.
I am looking for ideas on how to do this? Or suggestions on other approaches.
This won't be a complete answer, but I can help with the angularFire portion, and probably an angular guru can fill in the blanks for you (see //todo).
First of all, don't try to share scope. Simple pass the variables you want into the child scope. Since you'll want a 3-way binding, you can use & to call a method on the parent scope.
For example, to set up this pattern:
<div ng-repeat="(key,widget) in widgets">
<data-widget bound-widget="getBoundWidget(key)"/>
</div>
You could set up your directive like this:
.directive('dataWidget', function() {
return {
scope: {
boundWidget: '&boundWidget'
},
/* your directive here */
//todo presumably you want to use controller: ... here
}
});
Where &boundWidget invokes a method in the parent $scope like so:
.controller('ParentController', function($scope, $firebase) {
$scope.widgets = $firebase(/*...*/);
$scope.getBoundWidget = function(key) {
var ref = $scope.widgets.$child( key );
// todo, reference $scope.boundWidget in the directive??
ref.$bind(/*** ??? ***/);
};
});
Now you just need someone to fill in the //todo parts!
You still have access to the parent scope in the repeat. You just have to use $parent.
Controller
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.someParentScopeVariable = 'Blah'
$scope.data = [];
$scope.data.push({name:"fred"});
$scope.data.push({name:"frank"});
$scope.data.push({name:"flo"});
$scope.data.push({name:"francis"});
}]);
HTML
<body ng-controller="MainCtrl">
<table>
<tr ng-repeat="item in data | filter: search">
<td>
<input type="text" ng-model="$parent.someParentScopeVariable"/>
<input type="text" ng-model="item.name">
</td>
</tr>
</table>
</body>
Plunker

Resources