I'm a bit stuck with a piece of code. I have a search field which calls a PHP function which looks into the database:
$this->_helper->layout->disableLayout();
$q = $this->getRequest()->getParam('q');
$product_db = new Products();
$this->view->products = $product_db->searchProduct($q);
foreach($this->view->products as $product)
{
....
}
The result of this gets loaded into my HTML page via JQuery:
var searchItem = function() {
if($('#json_search').val())
{
$('#search-resultlist').load('/search/quick/q/'+ $('#json_search').val() );
}
else {
$('#search-resultlist').html('');
}
}
HTML:
<div class="right-searchcontent" >
<input type="text" class="form-control" placeholder="Search ... " id="json_search">
</div>
<div class="right-searchresult">
<ul id="search-resultlist" >
<li >
</li>
</ul>
</div>
Now basically what I try to achieve is to create a 'search history'.
At first I tried it with a SESSION array in my search controller:
if(!isset($_SESSION['history'])) {
$_SESSION['history'] = array();
}
And in my function to show the database search results:
if(!empty($product)){
if(!in_array($product->naam, $_SESSION['history']))
{
$_SESSION['history'][] = $product->naam;
}
}
But this was storing ALL the values I ever searched for (like: 'sk', 'ah')
I just want the values I actually clicked on.
Can anyone point me in the right direction?
I've been trying to achieve my result with localStorage, but this wasn't going to give me the right solution. Also I tried using Cookies with this function:
var cookieList = function(cookieName) {
var cookie = $.cookie(cookieName);
var items = cookie ? cookie.split(/,/) : new Array();
return {
"add": function(val) {
//Add to the items.
items.push(val);
//Save the items to a cookie.
$.cookie(cookieName, items.join(','));
},
"remove": function (val) {
indx = items.indexOf(val);
if(indx!=-1) items.splice(indx, 1);
$.cookie(cookieName, items.join(',')); },
"clear": function() {
items = null;
//clear the cookie.
$.cookie(cookieName, null);
},
"items": function() {
return items;
}
}
}
But when I tried to alert list.items it just returned me the whole method.
I can achieve the product name when I click it, but I just don't know how I can store this into a SESSION or something else what I can achieve any time on any page..
$(document).on('click', 'a.searchItem', function(e){
e.preventDefault();
var search = $(this).attr('value'));
});
I'ts been fixed with the function I already had:
var cookieList = function(cookieName) {
var cookie = $.cookie(cookieName);
var items = cookie ? cookie.split(/,/) : new Array();
return {
"add": function(val) {
//Add to the items.
items.push(val);
//Save the items to a cookie.
$.cookie(cookieName, items.join(','));
},
"contain": function (val) {
//Check if an item is there.
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) { return i; }
}
return -1;
};
}
var indx = items.join(',').indexOf(val);
if(indx > -1){
return true;
}else{
return false;
} },
"remove": function (val) {
indx = items.indexOf(val);
if(indx!=-1) items.splice(indx, 1);
$.cookie(cookieName, items.join(',')); },
"clear": function() {
items = null;
//clear the cookie.
$.cookie(cookieName, null);
},
"items": function() {
return items;
}
}
}
When someone clicks on a search result it's added to the cookie list:
$(document).on('click', 'a.searchItem', function(e){
var search = $(this).attr('value');
var list = new cookieList("MyItems");
if(!list.contain(search)){
list.add(search);
}
});
And when opening the search box I show the results of the list:
jQuery.each(list.items(), function(index, value){
....
});
Maybe this will help someone out sometime..
Related
someone have any idea how i should modify the payment-lines in the POS,I want to add a type of credit card(like a many2one, I did it) but every time I add a line my option change to the first and also when the order is finished not save the value in pos.order -> statement_id.
enter image description here
here is my code:
function POS_CashRegister (instance, local) {
var pos = instance.point_of_sale;
var _t = instance.web._t;
var QWeb = instance.web.qweb;
var round_pr = instance.web.round_precision
const ParentOrder = pos.Order;
pos.PosModel.prototype.models.push({ //loaded model
model: 'pos.credit.card',
fields: ['id', 'name'],
domain: [['pos_active','=',true]],
loaded: function(self,credit_cards){ //pass parameters
self.credit_cards = credit_cards;
},
});
pos.PaymentScreenWidget = pos.PaymentScreenWidget.extend({
validate_order: function(options) {
var self = this;
var currentOrder = self.pos.get('selectedOrder');
var plines = currentOrder.get('paymentLines').models;
for (var i = 0; i < plines.length; i++) {
if(plines[i].cashregister.journal_id[1] === 'Tarjeta de Credito (PEN)')
{
var value = plines[i].node.firstElementChild.nextElementSibling.nextElementSibling.firstElementChild.value;
plines[i].set_credit_card(parseInt(value));
//console.log(plines[i].node.firstElementChild.nextElementSibling.nextElementSibling.firstElementChild.value);
//plines[i].node
}
}
console.log(currentOrder);
self._super(options);
},
render_paymentline: function (line) {
var self = this;
if(line.cashregister.journal_id[1] !== 'Tarjeta de Credito (PEN)'){
if (line.cashregister.currency[1] !== 'USD') {
return this._super(line);
} else {
var el_html = openerp.qweb.render('Paymentline', {widget: this, line: line});
el_html = _.str.trim(el_html);
var el_node = document.createElement('tbody');
el_node.innerHTML = el_html;
el_node = el_node.childNodes[0];
el_node.line = line;
el_node.querySelector('.paymentline-delete')
.addEventListener('click', this.line_delete_handler);
el_node.addEventListener('click', this.line_click_handler);
var sourceInput = el_node.querySelector('.source-input');
var convertedInput = el_node.querySelector('.converted-input');
sourceInput.addEventListener('keyup', function (event) {
el_node.line.set_usd_amount(event.target.value);
convertedInput.value = el_node.line.get_amount_str();
});
line.node = el_node;
return el_node;
}
}else {
return this._super(line);
}
},
});
pos.Paymentline = pos.Paymentline.extend({
initialize: function(attributes, options) {
this.amount = 0;
this.cashregister = options.cashregister;
this.name = this.cashregister.journal_id[1];
this.selected = false;
this.credit_card = false;
this.pos = options.pos;
},
set_credit_card: function(value){
this.credit_card = value;
this.trigger('change:credit_card',this);
},
get_credit_card: function(){
return this.credit_card;
},
export_as_JSON: function(){
return {
name: instance.web.datetime_to_str(new Date()),
statement_id: this.cashregister.id,
account_id: this.cashregister.account_id[0],
journal_id: this.cashregister.journal_id[0],
amount: this.get_amount(),
credit_card_id: this.get_credit_card(),
};
},
});
}
any suggestions?
You can create 2 journals here too. One for visa and another for master If you don't want that drop down there. Another way is you have to store selected option in a variable and then print that variable in front.
To store selected option initially assigned ids to each values of option and after then while validating order you can get that id of that field and from that id you can get your value. By this way also you can do that.
I have a select2 to select multiple options from a dropdown, i also have it selecting multiple options. Is there anyway of populating the input field with values that are selected on page load by changing its value in some way, so when the page is loaded there are options already selected.
part of my code as follows:
$('#fruitSelect').select2({
multiple: true,
placeholder: "Select fruits...",
data: FRUIT_GROUPS,
query: function (options) {
var selectedIds = options.element.select2('val');
var data = jQuery.extend(true, {}, FRUIT_GROUPS);
var selectableGroups = $.map(data, function (group) {
var areAllChildrenSelected = true,
parentMatchTerm = false,
anyChildMatchTerm = false;
if (group.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0) {
parentMatchTerm = true;
}
var i = group.children.length
while (i--) {
var child = group.children[i];
if (selectedIds.indexOf(child.id) < 0) {
areAllChildrenSelected = false;
};
if (options.term == '' || (child.text.toLowerCase().indexOf(options.term.toLowerCase()) >= 0)) {
anyChildMatchTerm = true;
}
else if (!parentMatchTerm) {
var index = group.children.indexOf(child);
if (index > -1) {
group.children.splice(index, 1);
};
};
};
return (!areAllChildrenSelected && (parentMatchTerm || anyChildMatchTerm)) ? group : null;
});
options.callback({ results: selectableGroups });
}
}).on('select2-selecting', function (e) {
var $select = $(this);
if (e.val == '') {
e.preventDefault();
$select.select2('data', $select.select2('data').concat(e.choice.children));
$select.select2('close');
}
});
JS Fiddle
I'm facing a problem in which if I need to enable the save button if at least one check box is selected which is inside ng-repeat.
When I click for the first time it works well but dosen't work for multiple check box clicks.
Below is the working plunker:
Disabling save button
I'm using ng-change to get the selected condition..
$scope.getSelectedState = () => {
var selectedCount = new Array();
for (var i in $scope.selected) {
selectedCount.push($scope.selected[i]);
}
var allTrue = selectedCount.every(function (k) { return k });
if (allTrue) {
$scope.isSelected = false;
} else {
$scope.isSelected = true;
}
}
just change your getSelectedState . see PLUNKER DEMO
like:
$scope.getSelectedState = function() {
$scope.isSelected = true;
angular.forEach($scope.selected, function(key, val) {
if(key) {
$scope.isSelected = false;
}
});
};
and you should use ng-repeat in <tr> tag instead of <body> tag according to your plunker demo.
How about this:
$scope.getSelectedState = () => {
var selectedCount = new Array();
for (var i in $scope.selected) {
selectedCount.push($scope.selected[i]);
}
$scope.isSelected = selectedCount.indexOf(true) !== -1 ? false : true;
}
You fill the array with the checkbox values and then check if that array contains true value with indexOf
Here is my suggestion. Whenever there is any checked item, it will make variable "isAnyTrue = true".
$scope.getSelectedState = () => {
var selectedCount = new Array();
var isAnyTrue = false;
for (var i in $scope.selected) {
if ($scope.selected[i] === true){
isAnyTrue = true;
}
selectedCount.push($scope.selected[i]);
}
var allTrue = selectedCount.every(function (k) { return k });
$scope.isSelected = !isAnyTrue;
}
Here is your updated app.js:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.selected = {};
$scope.outputType = [
{
"id": 1,
"name": "Coal"
},
{
"id": 2,
"name": "Rom"
},
{
"id": 3,
"name": "Waste"
}
];
$scope.months = ["JAN", "FEB"];
$scope.values = [];
$scope.isSelected = true;
$scope.getSelectedState = (id) => {
var selectedCount = 0;
for(var key in $scope.selected){
if($scope.selected[key]){
selectedCount++;
}
}
if(selectedCount!=0){
$scope.isSelected = false;
}else{
$scope.isSelected = true;
}
}
});
Do this:
$scope.isSelected = false;
$scope.getSelectedState = () => {
var atleastOneSelected = false;
for (var i in $scope.selected) {
atleastOneSelected = atleastOneSelected || $scope.selected[i];
}
$scope.isSelected = atleastOneSelected;
}
And have following in html part:
<button type="button" ng-disabled="!isSelected" ng-click="save()">Save</button>
I'm a bit late to the question and I saw everyone already gave you a lot of great tips.
I found something different you may like, that does not involve any controller (Javascript) code.
Here is the HTML for the checkbox :
<label class="checkbox" >
<input type="checkbox" class="form-control"
ng-model="selected[item.id]" ng-init="state = -1" ng-click="state = state * -1;$parent.validFields = $parent.validFields + state;" /><i></i>
</label>
And for the button :
<button type="button" ng-disabled="validFields <= 0" ng-click="save()">Save</button>
Basically the general idea is this one : you have a "validFields" counter that starts at 0 (= no field is activated). The button is displayed if this value is above 0.
Every checkbox has a "state", that is either 1 or -1. Everytime you click on a checkbox, it adds its state to the counter, indicating whether it is ON or OFF, and switches its states. The next time you click you "cancel" the previous value that was added to the validation.
Working Plunker link here : PLUNKER DEMO
Happy coding!
call on ng- change function, (checkbox is in ng-repeat):
<input type="checkbox" name="selected" ng-model="library.isSelected" ng-change="auditCtrl.showButton()"/>
<button class="btn btn-primary" type="button" ng-click="auditCtrl.sendApproval()" ng-disabled="!auditCtrl.showSend">Send</button>
.js
auditCtrl.showButton = function()
{
var arrayCheck = [];
for(var k = 0; k < auditCtrl.libraries.length; k++)
{
if(auditCtrl.libraries[k].isSelected == true)
{
arrayCheck.push(auditCtrl.libraries[k]);
}
}
if(arrayCheck.length > 0)
{
auditCtrl.showSend = true;
}
else
{
auditCtrl.showSend = false;
}
}
The code below is simplified, see the fiddle: http://jsfiddle.net/QTUqD/7/
Basically I'm setting the device name under the data-bind, but I also need to specify the optionsValue for sending off to the database, but when I set it, the display data-bind is blank.
<script id="extItems" type="text/html">
<tr>
<td data-bind="text: device() && device().name"></td>
</tr>
</script>
<script id="editExts" type="text/html">
<tr>
<td>
<select data-bind="options: $root.devicesForItem($data), optionsText: 'name', value: device, optionsValue: 'id'"></select>
</td>
</tr>
</script>
window.ExtListViewModel = new function () {
var self = this;
window.viewModel = self;
self.list = ko.observableArray();
self.pageSize = ko.observable(10);
self.pageIndex = ko.observable(0);
self.selectedItem = ko.observable();
self.extQty = ko.observable();
self.devices = ko.observableArray();
self.addressList = ko.observableArray(['addressList']);
self.availableDevices = ko.computed(function() {
var usedQuantities = {}; // for each device id, store the used quantity
self.list().forEach(function(item) {
var device = item.device();
if (device) {
usedQuantities[device.id] = 1 + (usedQuantities[device.id] || 0);
}
});
return self.devices().filter(function(device) {
var usedQuantity = usedQuantities[device.id] || 0;
return device.qty > usedQuantity;
});
});
// need this to add back item's selected device to its device-options,
// and to maintain original order of devices
self.devicesForItem = function(item) {
var availableDevices = self.availableDevices();
return self.devices().filter(function(device) {
return device === item.device() || availableDevices.indexOf(device) !== -1;
});
}
self.edit = function (item) {
if($('#extMngForm').valid()) {
self.selectedItem(item);
}
};
self.cancel = function () {
self.selectedItem(null);
};
self.add = function () {
if($('#extMngForm').valid()) {
var newItem = new Extension();
self.list.push(newItem);
self.selectedItem(newItem);
self.moveToPage(self.maxPageIndex());
}
};
self.remove = function (item) {
if (confirm('Are you sure you wish to delete this item?')) {
self.list.remove(item);
if (self.pageIndex() > self.maxPageIndex()) {
self.moveToPage(self.maxPageIndex());
}
}
$('.error').hide();
};
self.save = function () {
if($('#extMngForm').valid()) {
self.selectedItem(null);
};
};
self.templateToUse = function (item) {
return self.selectedItem() === item ? 'editExts' : 'extItems';
};
self.pagedList = ko.dependentObservable(function () {
var size = self.pageSize();
var start = self.pageIndex() * size;
return self.list.slice(start, start + size);
});
self.maxPageIndex = ko.dependentObservable(function () {
return Math.ceil(self.list().length / self.pageSize()) - 1;
});
self.previousPage = function () {
if (self.pageIndex() > 0) {
self.pageIndex(self.pageIndex() - 1);
}
};
self.nextPage = function () {
if (self.pageIndex() < self.maxPageIndex()) {
self.pageIndex(self.pageIndex() + 1);
}
};
self.allPages = ko.dependentObservable(function () {
var pages = [];
for (i = 0; i <= self.maxPageIndex() ; i++) {
pages.push({ pageNumber: (i + 1) });
}
return pages;
});
self.moveToPage = function (index) {
self.pageIndex(index);
};
};
ko.applyBindings(ExtListViewModel, document.getElementById('extMngForm'));
function Extension(extension, name, email, vmpin, device, macAddress, shipTo){
this.extension = ko.observable(extension);
this.name = ko.observable(name);
this.email = ko.observable(email);
this.vmpin = ko.observable(vmpin);
this.device = ko.observable(device);
this.macAddress = ko.observable(macAddress);
this.shipTo = ko.observable(shipTo);
}
When you use optionsValue, KO writes the property value to whatever you have bound against value. So, it would now populate value with the id rather than the object.
There are a couple of ways to tackle this scenario where you want both the value (for sending to the DB) and the object (for binding other parts of the UI against).
A pretty typical solution is to create a computed observable on your object that takes the currently selected object and returns the id.
So, in your Extension you would do something like:
this.device = ko.computed({
read: function() {
var device = this.device.asObject();
return device && device.id;
},
deferEvaluation: true, //deferring evaluation, as device.asObject has not been created yet
}, this);
//create this as a sub-observable, so it just disappears when we turn this into JSON and we are just left with the id to send to the DB
this.device.asObject = ko.observable(device);
Then remove the optionsValue and bind value against device.asObject
In this case, I added the asObject sub-observable, so it will just drop off when you turn this into JSON (ko.toJSON) to send to the server. The only tricky part about this technique is that if you are loading existing data from the server, then you would need to populate asObject with the appropriate choice from your options.
Here is a sample: http://jsfiddle.net/rniemeyer/Q3PEv/
Another option that I have used is to continue to use optionsValue, but then to create a custom binding that tracks the object in a separate observable. Here is a custom binding that creates an asObject sub-observable for whatever is bound against value. This way you really don't need to mess with it at all in your view model.
//when using optionsValue, still track the select object in a different observable
ko.bindingHandlers.valueAsObject = {
init: function(element, valueAccessor, allBindingsAccessor) {
var value = allBindingsAccessor().value,
prop = valueAccessor() || 'asObject';
//add an "asObject" sub-observable to the observable bound against "value"
if (ko.isObservable(value) && !value[prop]) {
value[prop] = ko.observable();
}
},
//whenever the value or options are updated, populated the "asObject" observable
update: function(element, valueAccessor, allBindingsAccessor) {
var prop = valueAccessor(),
all = allBindingsAccessor(),
options = ko.utils.unwrapObservable(all.options),
value = all.value,
key = ko.utils.unwrapObservable(value),
keyProp = all.optionsValue,
//loop through the options, find a match based on the current "value"
match = ko.utils.arrayFirst(options, function(option) {
return option[keyProp] === key;
});
//set the "asObject" observable to our match
value[prop](match);
}
};
Sample here: http://jsfiddle.net/rniemeyer/E2kvM/
I'm working on an extension for Google Chrome and I ran into the following situation:
I'm trying to get all the existing tabs from all the opened windows in the same instance of Google Chrome. I manage to get them and construct an array of objects that contain the relevant data for me.
When I look at the constructed array using console.log (which is saved for future use also) I can see the collection of objects, but I can't reference them (when I try I get undefined).
I tried to save the array outside my object in a container, but nothing changes.
Any idea why the reference to the objects go away when I try to look them up? Thanks.
Here is the code:
(function(window){
//defining a namespace
var example = {
bmarksmaster: (function() {
var bmarksmaster = function() {
return new bmarksmaster.fn.init();
}
bmarksmaster.fn = bmarksmaster.prototype = {
debug: false,
tabs: [],
constructor: bmarksmaster,
init: function() {
return this;
},
windowParser: function(ctx, filter) {
var local = ctx;
var filter = filter;
return function(wObj) {
if((wObj !== null) && (wObj !== undefined)) {
for(var idx in wObj) {
var cw = wObj[idx];
if((cw.tabs !== null) && (cw.tabs !== undefined)) {
var cwtabs = cw.tabs;
for(var tabIdx in cwtabs) {
local.tabs.push(filter(tabIdx, cwtabs[tabIdx]));
}
}
}
}
};
},
getTabs: function() {
var returnData = [];
chrome.windows.getAll(
{
"populate": true
}, this.windowParser(this, function(i, e) {
var data = {};
if(!e.incognito) {
data["title"] = e.title;
data['url'] = e.url;
data['favicon'] = e.favIconUrl || "";
}
return data;
}));
return this.tabs;
},
getTab: function(callback) {
this.getTabs();
for (var tabIdx in this.tabs) {
if(callback(tabIdx, this.tabs[tabIdx])) {
return this.tabs[tabIdx];
}
}
},
getTabsData: function(callback) {
var data = [];
var tabs = [];
tabs = this.getTabs();
console.log(this.tabs[0]);
for (var tabIdx in tabs) {
console.log(tabs[tabIdx]);
var tabData = callback(tabIdx, tabs[tabIdx]);
if(tabData) {
data.push(tabData);
}
}
return data;
},
setDebug: function() {
this.debug = true;
},
resetDebug: function() {
this.debug = false;
}
};
bmarksmaster.fn.init.prototype = bmarksmaster.fn;
return bmarksmaster;
})()
};
window.example = example;
})(window);
//end of bmarksmaster.js file
console.log(example.bmarksmaster().getTabs()); //this works, I can see the array
console.log(example.bmarksmaster().getTabs()[0]); //this doesn't work, I get undefined, never mind the shortcut
I think the logic in your code is wrong. It is a bit convoluted and hard to follow. I would recommend rewriting it a bit to be simpler. Something like this might help get you started. It collects all the windows, putts all the tabs into the tabs var.
var tabs = [];
chrome.windows.getAll({ populate: true}, function(windows) {
var localTabs = windows.reduce(function(a, b){
return a.tabs.concat(b.tabs);
});
tabs = localTabs.filter(function(element){
return !element.incognito;
});
})