angular.module('plunker', ['jqSearchBox']).
controller('MainCtrl', function($scope) {
$scope.search = {
query: ''
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="angular.js@1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
<link rel="stylesheet" href="jquery.searchBox.css" />
<link rel="stylesheet" href="app.css" />
<script src="searchBox.js"></script>
<script src="searchBoxDirective.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div search-box ng-model="search.query" placeholder="Type in to search..."></div>
<p>Text to search: {{ search.query }}</p>
<p><input ng-model="search.query" /></p>
</body>
</html>
.search-box {
display: inline-block;
position: relative;
background: white;
margin-bottom: 10px;
}
.search-box input {
border: none;
outline: 0;
border-radius: 15px;
box-shadow: 1px 1px 12px -1px #eee inset;
background: white;
padding: 8px 22px 6px 10px;
margin: 0;
box-sizing: border-box;
font-size: 12px;
line-height: 12px;
color: #999;
}
.search-box span {
display: inline-block;
position: absolute;
z-index: 2;
right: 7px;
top: 7px;
width: 16px;
height: 16px;
color: #ccc;
}
.search-box span::before {
content: "";
display: block;
position: absolute;
float: left;
z-index: 2;
-webkit-transform: rotate(40deg);
transform: rotate(45deg);
width: 3px;
height: 7px;
margin: 7px 0 0 5px;
background: #ccc;
}
.search-box span::after {
content: "";
display: block;
float: right;
z-index: 3;
border: 1px solid #ccc;
border-radius: 50%;
width: 9px;
height: 9px;
box-sizing: border-box;
}
(function($, undefined) {
var template = '<div class="search-box"><input type="text" /><span></span></div>',
dataAttributeName = 'search-box',
arrSlice = Array.prototype.slice;
function SearchBox(element, options) {
this.$el = element;
element.html('').append(template);
var $input = this.$input = element.find('input'),
me = this;
if (options.placeholder) {
$input.attr('placeholder', options.placeholder);
}
if (typeof options.onchange === 'function') {
this.$change = options.onchange;
}
$input.on('keyup change', function(event) {
me.$change && me.$change(event, me.$input.val());
});
}
SearchBox.prototype = {
constructor: SearchBox,
$change: false,
$input: null,
$el: null,
setValue: function(value) {
this.$input.val(value);
},
getValue: function() {
return this.$input.val();
}
};
$.fn.searchBox = function(options) {
var args = arrSlice.call(arguments),
returnValue;
this.each(function() {
var $this = $(this),
data = $this.data(dataAttributeName);
if (!data) {
options = typeof options === 'object' && options || {};
data = new SearchBox($this, options);
$this.data(dataAttributeName, data);
}
if (typeof options === 'string' && typeof data[options] === 'function') {
args.shift();
returnValue = data[options].apply(data, args);
}
});
return returnValue !== undefined ? returnValue : this;
};
})(jQuery);
angular.module('jqSearchBox', []).
directive('searchBox', function() {
return {
restrict: 'A',
require: '?ngModel',
link: function($scope, $element, $attrs, ngModel) {
if (!ngModel) return;
$element.searchBox({
placeholder: $attrs.placeholder || '',
onchange: function(e, value) {
if (ngModel.$viewValue !== value) {
$scope.$apply(function() {
ngModel.$setViewValue(value);
});
}
}
});
ngModel.$render = function() {
$element.searchBox('setValue', ngModel.$viewValue || '');
};
}
};
});
* {
margin: 0;
padding: 0;
font-size: 1em;
}
body {
font-size: 13px;
font-family: sans-serif;
padding: 10px;
}