Angular js search input box - javascript

I have below search input box:
<div id="query-wrap">
<input ng-enter="startSearch('{{queryObj.query}}')" id="query" type="text" ng-model="queryObj.query"
placeholder="Enter Query" autocomplete="off" />
</div>
<a class="searchButton" ng-click='startSearch(queryObj.query)'>Search</a>
on click of search I am calling startsearch function:
$scope.startSearch = function(query) {
console.log("query is ::" + query);
// $location.path("/view");
$location.search({
q:query
});
getData();
}
Issue is: After submit is clicked proper query parameter is appended in the URL but sometimes query entered in search box is getting disappeared because of which I am not able to see proper results.
Below is my ng-enter directive:
app.directive('ngEnter', function () {
return function (scope, element, attrs, dropdownService) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
//If user presses an enter then fire an ESC event to not to show a dropdown
var e = angular.element.Event("keydown");
e.which = 27;
element.trigger(e);
scope.$eval(attrs.ngEnter);
event.preventDefault();
}
});
};
});

startSearch('{{queryObj.query}}') should be startSearch(queryObj.query). There's no reason to wrap that in an expression.

Related

jQuery trigger event on multiple fields with the same classname

I have multiple input fields that have the same class name, such as:
<input type="text" class="input-name" value="John">
<input type="text" class="input-name" value="Maria">
When someone presses ENTER in any field, the text !!! is automatically appended to the value. This works great.
$(document).on('keypress', '.input-name', function(event)
{
if (event.which != 13)
return;
$(this).val($(this).val() + '!!!');
});
The problem is that I'd like to press a button and change the value of all fields, by simulating the ENTER keypress event and for some reason, it only triggers in the first input!
This only triggers in the first input:
var e = $.Event('keypress', { which: 13 });
$('.input-name').trigger(e);
This also only triggers in the first input:
$('.input-name').each(function(i, input)
{
$(input).trigger(e);
});
You can see the problem in this JSFiddle.
Define jquery Event object inside the each function callback as follows.
$('.input-name').each(function (i, input) {
var e = $.Event('keypress', {
which: 13
});
$(input).trigger(e);
});
I would just make a function that does the work and not deal with event handlers
//function alterInps(inps) {
// inps.val(function () { return this.value + "!!!"; });
//}
function alterInps(inps) {
var re = /!!!$/;
inps.val(function () {
return this.value + (re.test(this.value) ? '' : '!!!');
});
}
$(document).on('keypress', '.input-name', function(event) {
if (event.which != 13) return;
alterInps($(this));
});
$('button').on("click", function () {
alterInps($('.input-name'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" class="input-name" value="John">
<input type="text" class="input-name" value="Maria">
<button type="buton">All</button>
$('.input-name').on('keypress', function(event)
{
if (event.which != 13)
return;
$(this).val($(this).val() + '!!!');
});
$(document).on('click', '#btn-submit', function()
{
var e = $.Event('keypress', { which: 13 });
//$('.input-name').trigger(e);
$('.input-name').each(function(i, input)
{
$(input).trigger(e);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-submit">
Click me
</button>
<input type="text" class="input-name" value="Maria">
<input type="text" class="input-name" value="John">

How to use the Angular jQuery Validate's checkForm() function

EDIT:
I've added a JsFiddle so you can easily troubleshoot instead of having to set up the environment yourself. As you can see, validation is done on the Email field even before the blur event on the input element, which was triggered by the $scope.Email being changed. If you comment out the ng-show="!mainForm.validate()" on the <p> element, you'll see that the issue doesn't take place.
I am using the Angular implementation of jQuery Validate, and I am in need of the ability to check if a form is valid without showing the error messages. The standard solution I've seen online is to use jQuery Validate's checkForm() function, like this:
$('#myform').validate().checkForm()
However, the Angular wrapper I'm using doesn't currently implement the checkForm function. I have been trying to modify the source code to bring it in, and I'm afraid I'm in over my head. The code is small and simple enough that I'll paste it here:
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
//This is the part I've tried adding in.
//It runs, but still shows error messages when executed.
//form.checkForm = function() {
// return validator.checkForm();
//}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
I want to be able to use it to show or hide a message, like this:
<p class="alert alert-danger" ng-show="!mainForm.checkForm()">Please correct any errors above before saving.</p>
The reason I don't just use !mainForm.validate() is because that causes the error messages to be shown on elements before they are "blurred" away from, which is what I'm trying to avoid. Can anyone help me implement the checkForm() function into this angular directive?
You can add checkForm() function to the plugin as following.
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.checkForm = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.checkForm();
validator.submitted = {};
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
Please find the updated jsFiddle here https://jsfiddle.net/b2k4p3aw/
Reference: Jquery Validation: Call Valid without displaying errors?
If I understand your question correctly, you want to be able to show an error message when the email adress is invalid and you decide you want to show the error message.
You can achieve this by setting the input type to email like this <input type=email>
Angular adds an property to the form $valid so you can check in your controller if the submitted text is valid. So we only have to access this variable in the controller and invert it. (Because we want to show the error when it is not valid)
$scope.onSubmit = function() {
// Decide here if you want to show the error message or not
$scope.mainForm.unvalidSubmit = !$scope.mainForm.$valid
}
I also added a submit button that uses browser validation on submit. This way the onSubmit function won't even get called and the browser will show an error. These methods don't require anything except angularjs.
You can check the updated JSFiddle here
Make sure to open your console to see when the onSubmit function gets called and what value gets send when you press the button.
You can use $touched, which is true as soon as the field is focused then blurred.
<p class="alert alert-danger" ng-show="mainForm.Email.$touched && !mainForm.validate()">Please correct any errors above before saving.</p>
you can achieve onblur event with ng-show="mainForm.Email.$invalid && mainForm.Email.$touched" to <p> tag
by default mainForm.Email.$touched is false, on blur it will change to true
for proper validation change the <input> tag type to email
you can add ng-keydown="mainForm.Email.$touched=false" if you don't want to show error message on editing the input tag
I didn't used angular-validate.js plugin
<div ng-app="PageModule" ng-controller="MainController" class="container"><br />
<form method="post" name="mainForm" ng-submit="OnSubmit(mainForm)" >
<label>Email:
<input type="email" name="Email" ng-keydown="mainForm.Email.$touched=false" ng-model="Email" class="email" />
</label><br />
<p class="alert alert-danger" ng-show="mainForm.Email.$invalid && mainForm.Email.$touched">Please correct any errors above before saving.</p>
<button type="submit">Submit</button>
</form>
</div>
Updated code : JSFiddle
AngularJs Form Validation
More info on Angular validation
Update 2
checkForm will return whether the form is valid or invalid
// added checForm, also adds valid and invalid to angular
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
to hide default messages adding by jQuery validation plugin add below snippet, to $.validator.setDefaults
app.config(function ($validatorProvider) {
$validatorProvider.setDefaults({
errorPlacement: function(error,element) { // to hide default error messages
return true;
}
});
});
here is the modified plugin looks like
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
var formName = validator.currentForm.name;
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
// added checkForm
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
controller
app.controller("MainController", function($scope) {
$scope.Email = "";
$scope.url = "";
$scope.isFormInValid = false; // to hide validation messages
$scope.OnSubmit = function(form) {
// here you can determine
$scope.isFormInValid = !$scope.mainForm.checkForm();
return false;
}
})
need to have following on every input tag(example for email)
ng-show="isFormInValid && !mainForm.Email.$invalid "
if the form and email both are invalid the validation message shows up.
JSFiddle
try this code for validation this is the form
<form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate>
<div class="form-group">
<input type="text" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" ng-model="name" name="name" class="form-control" placeholder="{{ 'regName' | translate }}" required>
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">Your name is required.</p>
</div>
<div class="form-group">
<input type="tel" ng-class="{ 'has-error' : userForm.mob.$invalid && !userForm.mob.$pristine }" ng-model="mob" class="form-control" name="mob" ng-maxlength="11" ng-minlength="11" ng-pattern="/^\d+$/" placeholder="{{ 'regPhone' | translate }}" required>
<p ng-show="userForm.mob.$invalid && !userForm.mob.$pristine" class="help-block">Enter a valid number</p>
</div>
<div class="form-group">
<input type="email" ng-model="email" name="email" class="form-control" placeholder="{{ 'regEmail' | translate }}" required>
<p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>
<div class="form-group">
<input type="password" ng-model="pass" name="pass" class="form-control" placeholder="{{ 'regPass' | translate }}" minlength="6" maxlength="16" required>
<p ng-show="userForm.pass.$invalid && !userForm.pass.$pristine" class="help-block"> Too short Min:6 Max:16</p>
<input type="password" ng-model="repass" class="form-control" ng-minlength="6" placeholder="{{ 'regConPass' | translate }}" ng-maxlength="16" required>
</div>
<button class="loginbtntwo" type="submit" id="regbtn2" ng-disabled="userForm.$dirty && userForm.$invalid" translate="signUp" ></button>
</form>
You will need to modify the Angular Validate Plugin a bit. Here is a working version of your code in JSFiddle. Note the updated plugin code as well as a pair of modifications to your original code.
Updated plugin code simply adds this to validator.SetDefaults parameter:
errorPlacement: function(error,element) { return true; } // to hide default error message
Then we use a scope variable to hide/show the custom error message:
$scope.OnSubmit = function(form) {
if (form.$dirty) {
if (form.validate()) {
//form submittal code
} else {
$scope.FormInvalid = true;
}
}

Shift+Enter in Textarea using AngularJS

This code shows how to use a directive to submit a form by hitting 'enter' while in a textarea. However, I would like to be able to shift+enter and go to the next line and submit the result as it is. Whenever the submission is made, it shows up in the same line. How do I submit and show the submitted text in the next line as the user intends.
<div ng-app="testApp" ng-controller="MyController">
<textarea ng-model="foo" enter-submit="submit()"></textarea><br/>
Last submitted text: {{ lastSubmitted }}<br/>
</div>
The AngularJS code:
var app = angular.module('testApp', []);
function MyController($scope) {
$scope.foo = ""
$scope.lastSubmitted = ""
$scope.submit = function() {
$scope.lastSubmitted = $scope.foo;
}
}
app.directive('enterSubmit', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('keydown', function(event) {
var code = event.keyCode || event.which;
if (code === 13) {
if (!event.shiftKey) {
event.preventDefault();
scope.$apply(attrs.enterSubmit);
}
}
});
}
}
});
What should I do?
It looks like you need to convert \n\r into <br/> then use ng-bind-html to sanitize the string.
Here is a code example
You will also have to include the angularjs sanitize js file:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular-sanitize.js"></script>

Meteor: form with two submit buttons (determine button clicked in event handler)

I have a simple form with two inputs: "title" and _"description", and two buttons: "save" (save for later) and "submit". For both I would want to get the values of my form fields and insert/update my collections accordingly.
<template name="NewScenarioForm">
<form id="newScenarioForm" >
<textarea type="text" id="title" name="title" rows="1" cols="75" placeholder="Type to add a title"></textarea><br/>
<textarea type="text" id="description" name="description" rows="4" cols="100" placeholder="Type to add a description" ></textarea><br/>
<input type="submit" id="saveScenarioButton" name="action" title="Save Scenario" value="Save" />
<input type="submit" id="submitScenarioButton" name="action" title="Submit for approval" value="Submit" />
</form>
</template>
Right now I'm detecting the event like this:
"click #saveScenarioButton": function(event, template) {
event.preventDefault();
var title = template.find("#title").value;
var description = template.find("#description").value;
...
//Do stuff with this information to persist information
Meteor.call("saveScenario", title, description);
....
}
And I need to repeat the whole function for the other button. I would would like to detect the event and determine which button was pressed instead.
I have been struggling with an event handler like:
"submit #newScenarioForm": function(event) {
But then I don't know how to determine the button clicked, since I can't figure out an event property. Is there a way to determine the button if I wanted to use the form ID in my event handler instead of the ID of each button (or a smarter way to approach this altogether?)?
You could make the event target inputs with type submit:
Template.NewScenarioForm.events({
"click input[type=submit]": function(e) {
if ($(e.target).prop("id") == "saveScenarioButton") {
// Save the scenario
} else if ($(e.target).prop("id") == "submitScenarioButton") {
// Submit the scenario
}
}
});
You could also make it check the clicked button's value, and drop the ID field
Please note that this will not handle other ways of submitting the form, for example the user pressing Enter in an input field. An approach to handle this as well could be to define a few functions:
function scrapeForm() {
// Collects data from the form into an object
}
function saveData() {
var formData = scrapeForm();
// More logic to save the data
}
function submitData() {
var formData = scrapeForm();
// More logic to submit the data
}
Template.NewScenarioForm.events({
"click input[type=submit]": function(e) {
if ($(e.target).prop("id") == "saveScenarioButton") {
saveData();
} else if ($(e.target).prop("id") == "submitScenarioButton") {
submitData();
}
},
"submit #NewScenarioForm":
// Default action on submit.
// Either save the data
saveData
// or submit the data
submitData
// or nothing, requiring the user to actually click one of the buttons
function(e) {e.preventDefault();}
});
Why not just give them both the same class like submitForm
<input class="submitForm"** type="submit" id="saveScenarioButton" name="action" title="Save Scenario" value="Save" />
<input class="submitForm" type="submit" id="submitScenarioButton" name="action" title="Submit for approval" value="Submit" />
then have a onClick for .submitForm like so:
$('.submitForm').on('click', function () {...});
and inside the function get id by doing:
var id = $(this).attr('id');
full code:
$('.submitForm').on('click', function () {
var id = $(this).attr('id');
... the rest of your code ...
});
I do this to correctly identify buttons using class or id.
helloWorld.html
<head>
<title>helloWorld</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
<button class="plus5">+5</button>
<button class="minu5">-5</button>
<button id="plus1">+1</button>
<button id="minu1">-1</button>
<p>You've pressed the button {{counter}} times.</p>
</template>
helloWorld.js
if (Meteor.isClient) {
// counter starts at 0
Session.setDefault('counter', 0);
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.events({
'click button.plus5': function () {
Session.set('counter', Session.get('counter') + 5);
},
'click button.minu5': function () {
Session.set('counter', Session.get('counter') - 5);
},
'click button#plus1': function () {
Session.set('counter', Session.get('counter') + 1);
},
'click button#minu1': function () {
Session.set('counter', Session.get('counter') - 1);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
click .plus5, click #plus1 also work.

inject HTML when enter key pressed on input

I have an input field and when people press enter I'd like the field to be emptied and its value printed below with an 'x' icon to delete it afterwards just like the 'search' field on angel.co: https://angel.co/jobs
Here is my HTML:
<form ng-submit="searchAds(searchInput)">
<input id="search-field" type="search" placeholder="Start typing your search..." ng-change="searchRequest()" ng-model="searchInput"/>
</form>
<div id="search-tags"></div>
And my JS in my controller:
$scope.searchAds = function(item){
if (item === "") return;
$scope.searchInput = "";
$('#search-tags').append('<div ng-show="showDetails">' + item + '<div ng-click="showDetails = ! showDetails"> (my DVG icon here) </div></div>');
}
I have 2 problems here:
1 - I believe the code is not compiled when printed so the 'ng-show' and 'ng-click' are so working - how can I make this work?
2 - How can I make sure that when there are several tags, when clicking on my delete icon it hide only this specific tag?
Many thanks
Why not angular instead of jQuery?
You can add a directive to manage the "enter" key:
angular.module('yourModule').directive(
'ngEnter',
function () {
'use strict';
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
And then change a bit your code:
<form ng-submit="searchAds(searchInput)">
<input type="search" placeholder="Start typing your search..." ng-enter="add(searchInput)" ng-model="searchInput"/>
</form>
<div ng-repeat="tag in tags">
<div>{{tag}}<div ng-click="delete(tag)">(my DVG icon here)</div></div>
</div>
Your controller:
$scope.add = function(item) {
$scope.tags.push(item);
$scope.searchInput = "";
}
$scope.delete = function(item) {
var index = $scope.tags.indexOf(item);
$scope.tags.splice(index, 1);
}

Categories