Stop AngularJS Instant Search - javascript

I have built a simple search form in my AngularJS app, that as you type uses the built in filter magic of angular to filter a list of phones. I've wrapped mine in a form as when the user submits the form it ALSO does the filter, but creates a query string so you can navigate away from the list and return etc.
HTML:
<form class="form-search" ng-submit="$parent.queryChanged()">
<div class="control-group">
<label class="control-label" for="filter">Filter:</label>
<div class="controls">
<input name="q" ng-model="$parent.query" id="filter" type="text">
</div>
</div>
</form>
JS:
phonecatControllers.controller('PhoneListCtrl', ['$scope', 'Phone', '$location',
function($scope, Phone, $location) {
$scope.query = $location.search()['q'];
$scope.queryChanged = function () {
$location.search('q', $scope.query)
}
$scope.phones = Phone.query();
$scope.orderProp = 'age';
}]);
What I want to do is disable the instant search, so the user ONLY submits the form and never gets the results on keyup alone. How do I do this?

Use 2 different variables for the ng-model of the input (ng-model="$parent.query") and the parameter of the filter (| filter:filterQuery). This will make the input and the filter unrelated to each other. Then when the form is submitted (in queryChanged), update the filter parameter with the value of the ng-model ($scope.filterQuery = $scope.query).

Related

AngularJS not sending hidden input value

I'm trying to get data from my form in AngularJS, this all works fine except for the field I did not type anything in. I changed the field from hidden to text, but both do not work, however if you inspect element you can see the correct value in it. Here's my HTML:
<div ng-controller="postMessageCtrl as Ctrl">
<form ng-submit="processMessage()">
<div class="form-group">
<input type="message" class="form-control" placeholder="Message" ng-model="formData.message">
a{{data.receiver.id}}a
<input type="hidden" class="form-control" ng-model="formData.receiver" ng-value="data.receiver.id" />
</div>
<button type="submit" class="btn btn-primary btnq-lg btn-block">Verzenden</button>
</form>
</div>
And here's my controller:
app.controller('postMessageCtrl', function ($scope, $http, $state, localStorageService) {
$scope.formData = {};
//$scope.formData = localStorageService.get('userKey');
$scope.formData = {
key: localStorageService.get('userKey'),
message: '',
receiver: ''
};
console.log($scope.formData);
});
The key and message are filled correctly, but the receiver id is not. any suggestions?
From the answer AngularJS does not send hidden field value:
You cannot use double binding with hidden field. The solution is to use brackets:
<input type="hidden" name="someData" value="{{data}}" /> {{data}}
See this thread on GitHub: https://github.com/angular/angular.js/pull/2574
Since Angular 1.2, you can use ng-value directive to bind an expression to the value attribute of input. This directive should be used with input radio or checkbox but works well with hidden input.
Here is the solution using ng-value:
<input type="hidden" name="someData" ng-value="data" />
Update:
Another solution could be to directly set the value in $scope.formData rather using the hidden input field when you are initializing it:
$scope.formData = {};
//$scope.formData = localStorageService.get('userKey');
$scope.formData = {
key: localStorageService.get('userKey'),
message: '',
receiver: ''
};
$scope.formData.receiver = $scope.data.receiver.id // Set the value directly in your `formData` since you are using Angular;
console.log($scope.formData);
The simple solution is to use ngInit directive:
<input type="hidden" class="form-control"
ng-model="formData.receiver"
ng-init="formData.receiver = data.receiver.id" />
Avoid submit complexion by just handling things with a function call on a button click, like on this Plunk.
Html:
<div ng-controller="postMessageCtrl as Ctrl">
<form>
<div class="form-group">
<input type="message" class="form-control" placeholder="Message" ng-model="messageInput">
<button ng-click="Add()">Add</button>
<p></p>
<button type="submit" class="btn btn-primary btnq-lg btn-block" ng-click="Send()">Send</button>
</div>
<p></p>
<b>Messages</b>
<ul>
<li ng-repeat="message in formData.messages">{{message}}</li>
</ul>
</form>
</div>
AngularJS Controller:
app.controller("postMessageCtrl", [
"$scope",
"$http",
function($scope, $http){
var self = {};
$scope.messageInput = '';
$scope.formData = {
key: 'someUserKey',
messages: [],
receiver: null
};
$scope.Add = function(){
console.log($scope.messageInput);
if($scope.messageInput.length > 0) {
$scope.formData.messages.push($scope.messageInput);
}
};
$scope.Send = function() {
console.log($scope.formData);
$http.post("/somehost/action/", $scope.Person).success(function(data, status) {
$scope.hello = data;
});
};
}]);
The sample will have a 400 bad request error in console, because the url used is obviously not going to work, but the principle is correct.
This way you don't even need to add hidden fields, because they aren't needed (you always have their value from $scope.Person).
Conclusion:
There are 2 things that didn't make sense from your original question:
a{{data.receiver.id}}a
You should use formData here, data isn't defined.
JSON is incorrect
Receiver doesn't contain id, given your sample code, it should be defined like so:
$scope.formData = {
key: localStorageService.get('userKey'),
message: '',
receiver: {
id: 1,
name: 'SomeReceiver'
}
};
So if your receiver is set like this:
$scope.formData.receiver = $scope.formData.messages[0].receiver;
You will need to implement some way of providing that receiver through messages[0];
You'll notice that the receiver becomes an Object in the console log.

Undefined value from text area in AngularJS

I am creating one form using Bootstrap & AngularJS. I am using CK editor in my page as textarea. But I am not able to retrieve the value of the textarea while the value of the input text field is easily captured in my AngularJS controller. Following is the code snippet:
HTML page:
<div class="container">
<div ng-controller="controller">
<form role="form">
<label for="sd"><b>Short Description: </b></label>
<input ng-model="sdesc" class = "form-control input-xxlarge" type = "text" placeholder ="Provide a short description here."/>
<br/>
<label for="dt"><b>Details: </b></label>
<textarea ng-model="details" class="form-control" name="details_editor" id="details_editor"></textarea>
<br/>
<button class = "btn btn-primary" ng-click="submitted()">Ask It!</button>
<script>
CKEDITOR.replace('details_editor');
</script>
</form>
</div>
<br/>
<hr>
</div>
JS
app.controller('controller', ['$scope', function($scope){
$scope.submitted = function(){
var sdesc = $scope.sdesc;
var details = $scope.details;
alert($scope.details);
};
}]);
The alert shows undefined for the text area value.
Please help me solve the issue.
You are using the plain Javascript version of CK editor and hence Angular is not getting notified to update the ng-model value of that textarea.
Basically, Angular runs a digest cycle to update all views and models but since in this case the values being changed in the CK editor is happening outside the Angular.s context which is not updating the ng-model value.
To fix this, we added a small directive and notifying the change in the ng-model to the Angular by using the $timeout. (We can also use the $apply directive, but it may fail sometimes if the digest cycle is already in progress)
Example directive:
var app = angular.module("your-app-name", []);
app.directive("ckEditor", ["$timeout", function($timeout) {
return {
require: '?ngModel',
link: function ($scope, element, attr, ngModelCtrl) {
var editor = CKEDITOR.replace(element[0]);
console.log(element[0], editor);
editor.on("change", function() {
$timeout(function() {
ngModelCtrl.$setViewValue(editor.getData());
});
});
ngModelCtrl.$render = function (value) {
editor.setData(ngModelCtrl.$modelValue);
};
}
};
}]);
Remove, your following code:
<script>
CKEDITOR.replace('details_editor');
</script>
And, modify your text-editor like:
<textarea ng-model="details" class="form-control" ck-editor name="details_editor" id="details_editor"></textarea>
I found ng-ckeditor to implement ckeditor in angularjs.
Please refer this :https://github.com/esvit/ng-ckeditor. I tried it, It is easy to implement and working as expected

Angularjs - assigning logic between two models

I am new to Angular. It is a very simple question -
in my index.html I am defining two models on two text boxes :-
<html><head><script...></head><body ng-app="myApp"ng-controller="MainController" >
<input ng-model="tb1" type="text" name="numberofusers"/>
<input ng-model="tb2" type="text"></input>
</body></html>
And in my app.js I am defining like this
var app = angular.module('myApp', []);
app.controller('MainController', ['$scope', function($scope){
$scope.tb1 = $scope.tb2;
}]);
Now, what I want is that whatever I type in first text box (tb1) automatically typed to second text box (tb2) and vise-versa, but that is not happening.
Any guess ?
Your code in controller $scope.tb1 = $scope.tb2; would only be executed once (when controller initializes), that's why it doesn't work.
You need to bind input elements to the same model then Angular will handle two-way binding for you automatically.
<input ng-model="tb1" type="text" name="numberofusers"/>
<input ng-model="tb1" type="text"></input>
Or if you want to use two different models for different elements, you can add a hook to input's ng-change event listener like
<input ng-model="tb1" type="text" name="numberofusers" ng-change="tb2 = tb1"/>
<input ng-model="tb2" type="text" ng-change="tb1 = tb2"></input>
Then these two elements would sync automatically. But you know what, ng-change can only monitor user input change, that means, if you change tb1 or tb2 programmably, ng-change will not be triggered.
In this case, you should monitor model's change using $scope.$watch
$scope.$watch('tb1', function(newValue) {
$scope.tb2 = newValue;
}));
Currently it's beyond your requirement.
This is because controller will only execute once and if there is any value in $scope.tb2 will assign to $scope.tb1 but intially both of them are blank .
So you need to $watch the changes and assign value to each other like :-
$scope.$watch('tb1',function(newVal){
$scope.tb2=newVal;
})
$scope.$watch('tb2',function(newVal){
$scope.tb1=newVal;
})
And if you want to manage it on front end you can use ng-change directive like
<input ng-model="tb1" type="text" ng-change="tb2=tb1" name="numberofusers"/>
<input ng-model="tb2" type="text" ng-change="tb1=tb2"></input>
You can use two-way binding to achieve that. An example is: JSFiddle
Create your directive:
var app = angular.module('myApp', []);
app.controller("myCtrl", function($scope) {
$scope.myName = 'Carl';
}).directive("myDirective", function() {
return {
restrict: 'AE',
scope: {
twowayBindingProp: '=myName'
}
}
});
And bind it through:
<div ng-app="myApp">
<div ng-controller="myCtrl">
<h1>From parent: </h1>
<h3>parentProp2: <input ng-model="myName"></h3>
<div my-directive my-name="myName">
<h1>From child: </h1>
<h3>twowayBindingProp: {{ twowayBindingProp }}</h3>
<h1>Set from child:</h1>
twowayBindingProp: <input ng-model="twowayBindingProp">
</div>
</div>
</div>

AngularJS does not send hidden field value

For a specific use case I have to submit a single form the "old way". Means, I use a form with action="". The response is streamed, so I am not reloading the page. I am completely aware that a typical AngularJS app would not submit a form that way, but so far I have no other choice.
That said, i tried to populate some hidden fields from Angular:
<input type="hidden" name="someData" ng-model="data" /> {{data}}
Please note, the correct value in data is shown.
The form looks like a standard form:
<form id="aaa" name="aaa" action="/reports/aaa.html" method="post">
...
<input type="submit" value="Export" />
</form>
If I hit submit, no value is sent to the server. If I change the input field to type "text" it works as expected. My assumption is the hidden field is not really populated, while the text field actually is shown due two-way-binding.
Any ideas how I can submit a hidden field populated by AngularJS?
You cannot use double binding with hidden field.
The solution is to use brackets :
<input type="hidden" name="someData" value="{{data}}" /> {{data}}
EDIT : See this thread on github : https://github.com/angular/angular.js/pull/2574
EDIT:
Since Angular 1.2, you can use 'ng-value' directive to bind an expression to the value attribute of input. This directive should be used with input radio or checkbox but works well with hidden input.
Here is the solution using ng-value:
<input type="hidden" name="someData" ng-value="data" />
Here is a fiddle using ng-value with an hidden input: http://jsfiddle.net/6SD9N
You can always use a type=text and display:none; since Angular ignores hidden elements. As OP says, normally you wouldn't do this, but this seems like a special case.
<input type="text" name="someData" ng-model="data" style="display: none;"/>
In the controller:
$scope.entityId = $routeParams.entityId;
In the view:
<input type="hidden" name="entityId" ng-model="entity.entityId" ng-init="entity.entityId = entityId" />
I've found a nice solution written by Mike on sapiensworks. It is as simple as using a directive that watches for changes on your model:
.directive('ngUpdateHidden',function() {
return function(scope, el, attr) {
var model = attr['ngModel'];
scope.$watch(model, function(nv) {
el.val(nv);
});
};
})
and then bind your input:
<input type="hidden" name="item.Name" ng-model="item.Name" ng-update-hidden />
But the solution provided by tymeJV could be better as input hidden doesn't fire change event in javascript as yycorman told on this post, so when changing the value through a jQuery plugin will still work.
Edit
I've changed the directive to apply the a new value back to the model when change event is triggered, so it will work as an input text.
.directive('ngUpdateHidden', function () {
return {
restrict: 'AE', //attribute or element
scope: {},
replace: true,
require: 'ngModel',
link: function ($scope, elem, attr, ngModel) {
$scope.$watch(ngModel, function (nv) {
elem.val(nv);
});
elem.change(function () { //bind the change event to hidden input
$scope.$apply(function () {
ngModel.$setViewValue( elem.val());
});
});
}
};
})
so when you trigger $("#yourInputHidden").trigger('change') event with jQuery, it will update the binded model as well.
Found a strange behaviour about this hidden value () and we can't make it to work.
After playing around we found the best way is just defined the value in controller itself after the form scope.
.controller('AddController', [$scope, $http, $state, $stateParams, function($scope, $http, $state, $stateParams) {
$scope.routineForm = {};
$scope.routineForm.hiddenfield1 = "whatever_value_you_pass_on";
$scope.sendData = function {
// JSON http post action to API
}
}])
I achieved this via -
<p style="display:none">{{user.role="store_user"}}</p>
update #tymeJV 's answer
eg:
<div style="display: none">
<input type="text" name='price' ng-model="price" ng-init="price = <%= #product.price.to_s %>" >
</div>
I had facing the same problem,
I really need to send a key from my jsp to java script,
It spend around 4h or more of my day to solve it.
I include this tag on my JavaScript/JSP:
$scope.sucessMessage = function (){
var message = ($scope.messages.sucess).format($scope.portfolio.name,$scope.portfolio.id);
$scope.inforMessage = message;
alert(message);
}
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
<!-- Messages definition -->
<input type="hidden" name="sucess" ng-init="messages.sucess='<fmt:message key='portfolio.create.sucessMessage' />'" >
<!-- Message showed affter insert -->
<div class="alert alert-info" ng-show="(inforMessage.length > 0)">
{{inforMessage}}
</div>
<!-- properties
portfolio.create.sucessMessage=Portf\u00f3lio {0} criado com sucesso! ID={1}. -->
The result was:
Portfólio 1 criado com sucesso! ID=3.
Best Regards
Just in case someone still struggles with this, I had similar problem when trying to keep track of user session/userid on multipage form
Ive fixed that by adding
.when("/q2/:uid" in the routing:
.when("/q2/:uid", {
templateUrl: "partials/q2.html",
controller: 'formController',
paramExample: uid
})
And added this as a hidden field to pass params between webform pages
<< input type="hidden" required ng-model="formData.userid" ng-init="formData.userid=uid" />
Im new to Angular so not sure its the best possible solution but it seems to work ok for me now
Directly assign the value to model in data-ng-value attribute.
Since Angular interpreter doesn't recognize hidden fields as part of ngModel.
<input type="hidden" name="pfuserid" data-ng-value="newPortfolio.UserId = data.Id"/>
I use a classical javascript to set value to hidden input
$scope.SetPersonValue = function (PersonValue)
{
document.getElementById('TypeOfPerson').value = PersonValue;
if (PersonValue != 'person')
{
document.getElementById('Discount').checked = false;
$scope.isCollapsed = true;
}
else
{
$scope.isCollapsed = false;
}
}
Below Code will work for this IFF it in the same order as its mentionened
make sure you order is type then name, ng-model ng-init, value. thats It.
Here I would like to share my working code :
<input type="text" name="someData" ng-model="data" ng-init="data=2" style="display: none;"/>
OR
<input type="hidden" name="someData" ng-model="data" ng-init="data=2"/>
OR
<input type="hidden" name="someData" ng-init="data=2"/>

Trying to update one input's value to another's using angularjs

I'm fairly new using AngularJS but I've been using for a pet project and I've run in to an issue. What I basically want to do is take the text input from this input field:
<form id="ci_search_form">
<p class="input-append"><label>Search:</label> <input type="text" id="query" ng:model="query" autofocus> <button ng:click="clearSearch()" class="btn"><i class="icon-remove"></i></button></p>
</form>
and update this input field's value with that value:
<div><input type="text" id="ciquery" ng:model="ciquery.Name"></div>
The second input filters some data and I can type in that directly and it works. However this page will have different sets of data, each with their own search input that I want updated by the master input at the top. I can't set value="" or use jQuery to set the value either, it just appears blank unless I explicitly type in that second input field. Can anyone assist with a solution?
EDIT
I thought I should include my app and controller code:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.clearSearch = function(){
$scope.query = '';
}
});
EDIT 2
Made some progress. Created a function that can be called an update ciquery in $scope:
var App = angular.module('TicketAssistApp', []);
App.controller('SearchController', function($scope, $http, $filter){
$scope.query = '';
$scope.ciquery = '';
$http.get('static/ci_list.json').success(function(data){
$scope.ci_list = data;
});
$scope.queryUpdate = function(){
$scope.ciquery = $scope.query;
}
$scope.clearSearch = function(){
$scope.query = '';
$scope.queryUpdate();
}
});
This works great. However, this creates another issue. Before in ciquery I was using ciquery.Name to filter only on the Name attribute. With this new solution I had to change it to this:
<div><input type="hidden" id="ciquery" ng:model="ciquery"></div>
This searches all fields in my data which returns unwanted results. Suggestions?
$scope and ng-model are differents. You should give ng-model's property to ng-click's function. Looks at this -> Ng-model does not update controller value
To update second input's field (here an example -> http://jsfiddle.net/yEvSL/1/)
<div><input type="text" id="ciquery" ng:model="query"></div>

Categories