How to add content via ajax using the popover boostrap - javascript

I tried to view different sources and also looked into the forums posting similar question, but it didnt quite help me with the issue that im facing.
I have a text input filed to which I'm adding a popover to show similar a list of names in the database. The inout field checks for validation, to see if the name entered is unique, if not it displays similar names available in the database that could be re-used.
here is the popover snippet:
$("#account_name_create").popover({
title: 'Twitter Bootstrap Popover',
content: function (process) {
this.accountCollection = new ipiadmin.collections.AccountCollection();
var newName = $("#new-account-form #account_name_create").val();
var userFilter = "accountName~'" + newName + "'";
this.accountCollection.fetch({
data: { "f": userFilter,
"sortby": null,
"type":"ipi",
"pageno":0,
"pagesize":2,
"reversesort" : true
},
cache: false,
success: function(model, response, options) {
var states = [];
map = {};
$.each(model.aDataSet, function (i, state) {
map[state.accountName] = state;
states.push(state.accountName);
});
process(states); //gives an error saying 'undefined is not a function (says process is undefined)'
},
error: function(model, response, options) {
console.log('error');
}
});
},
});
here is the html:
<input type="text" id="account_name_create" name="account_name" class="" size="40" />
I'm not sure how why it says 'process' as undefined. Also not sure if this would be the correct way of displaying the data in the popover.
Any ideas??
Thanks!

process doesn't have scope in the success function, only in the content function. If you want to call the process function from within the success function, you could define it somewhere outside of the jQuery call.

Related

How can ajax based Select2 pre-population be formatted?

We've found several examples of pre-populating selected option for Select2, however none of them we could find deal with formatted list and selection options. We have a JS fiddle at https://jsfiddle.net/gpsx62de/26/ that illustrates the issue. In that fiddle, you can type and L or whatever into the select search and the data is returned, the list is formatted, and if you select something, the selection is formatted.
However if you click the button in that JS Fiddle which is intended to simulate pre-population per https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2 the data is returned (you can uncomment the console.log to see it), but the formatted selection shows undefined for the intended values. Does anyone know of a way to get the formatted values for pre-populated data to display correctly?
// Set up the Select2 control
$('#mySelect2').select2({
ajax: {
url: '/api/students'
}
});
// Fetch the preselected item, and add to the control
var studentSelect = $('#mySelect2');
$.ajax({
type: 'GET',
url: '/api/students/s/' + studentId
}).then(function (data) {
// create the option and append to Select2
var option = new Option(data.full_name, data.id, true, true); //**** DOES IT MATTER WHAT IS PASSED HERE BECAUSE WE ARE NOT DISPLAY THE OPTION TEXT?? ***
studentSelect.append(option).trigger('change');
// manually trigger the `select2:select` event
studentSelect.trigger({
type: 'select2:select',
params: {
data: data //**** THIS DOES NOT SEEM TO SUPPORT FORMATTED SELECTIONS, SO HOW CAN THIS BE DONE? ***
}
});
});
The problem is in format_selection function. The format of the object it receives depends on how it was created. When you use new Option(text, value) it receives only the properties of this Option object, not your original object containing all user info.
A workaround is to check of either possible values in the fuction:
function format_selection(obj) {
let name = obj.name || obj.element.text;
let email = obj.email || obj.element.email;
return $(`<div><b>${name}</b></div><div>(${email})</div>`);
}
For this to work you should append the de property on you Option object:
var option = new Option(data.name, data.id, true, true);
option.email = data.email;
$('#sel').append(option).trigger('change');
The problem, in https://jsfiddle.net/gpsx62de/26/ is with the
function format_selection(obj) {
// Just add this to see the obj
console.log(obj);
return $(`<div><b>${obj.text}</b></div><div>(${obj.id})</div>`);
}
The obj object just contains the Option class data, so:
id: "1",
selected: true,
text: "Leanne Graham",
title: ""
So you have to find a way to pass "data.email" to the "format_selection" method
EDIT
This could be a solution
$('#btn').on('click', function() {
$.ajax({
type: 'GET',
url: 'https://jsonplaceholder.typicode.com/users/1'
})
.then(function(data) {
console.log(data)
// create the option and append to Select2
$('#sel').append($('<option />') // Create new <option> element
.val(data.id) // Set value
.text(data.name) // Set textContent
.prop('selected', true)
.attr('data-name', data.name) // Don't know why the .data(key, value) isn't working...
.attr('data-email', data.email))
.trigger('change');
}); //then
}); //click
And
function format_selection(obj) {
return $(`<div><b>${obj.element.dataset.name}</b></div><div>(${obj.element.dataset.email})</div>`);
}
This is the fiddle https://jsfiddle.net/947jngtu/

Input with autocomplete jquery and Odoo rpc call don't show suggestions

I want use the jquery autocomplete for loading data from backend when the user still pressing keys.
I see that site for making autocomplete with ajax call.
Here the code that i'm using but i'm stucked with results.
I don't understand how the autocomplete take back odoo rpc result and show it in the input form
<label class="control-label" for="timesheet_user_id">Employee:
</label>
<input id="employee_name"/>
And jquery autocomplete
var employee_name = $('#employee_name');
employee_name.autocomplete({
source: function (request, response) {
ajax.jsonRpc("/employee_search", "call", {"name": employee_name.val()})
.then(function (data) {
response(data);
console.debug(response);
});
},
onSelect: function (suggestion) {
alert('You selected: ' + suggestion.value + ', ' + suggestion.data);
}
});
By console i see that i receive the array of objects but nothing happens on html.
Maybe is wrong the type of data or how i make the rpc call?
Backend function:
#http.route("/employee_search", type="json",
auth="public", website=True)
def employee_search(self, name):
employee_objs = request.env["hr.employee"] \
.sudo().search([("name", "ilike", name)])
if not employee_objs:
return {"fail": True}
suggestions = []
for employee in employee_objs:
employee_vals = {}
employee_vals['value'] = employee.id
employee_vals['data'] = employee.name
suggestions.append(employee_vals)
# make a dict of dicts with employees values
return suggestions
EDIT
Modified into jquery autocomplete the response = data; with
.then(function (data) {
response(data);
console.debug(response);
});
Now the input show two little boxes without text inside.
The received data from rpc call still not shown after input box
EDIT2
the problem is the source:, because if i pass an array of static object i can see them, but with this call nothing happends....where i'm wrong?
employee_name.autocomplete({
source: function (request, response) {
ajax.jsonRpc("/employee_search", "call", {"name": employee_name.val()})
.then(function (data) {
response(data);
console.debug(response);
});
}
});
Data contain the array of values but source don't catch them.
Ok i finally write a code that work for a real time search with suggestions:
Here the JS:
/*Autocomplete that suggest input*/
var serial_number = $('#searchSerial');
serial_number.autocomplete({
minLength: 3,
source: function (request, response) {
ajax.jsonRpc("/serial_search", "call", {"serial": serial_number.val()})
.then(function (data) {
console.debug(data);
if (data.fail) {
// if SN was not found in the db alert the user
// This is non blocking, the user can still compile the form
//alert(_t("Serial Number not found in the system, please fill the form manually"));
serial_number.addClass('error_input');
} else {
serial_number.removeClass('error_input');
response(data);
}
});
},
//If the record return is only one auto select it
response: function (event, ui) {
if (ui.content.length === 1) {
ui.item = ui.content[0];
serial_number.val(ui.item.value);
serial_number.data('ui-autocomplete')._trigger('select', 'autocompleteselect', ui);
serial_number.autocomplete('close');
}
},
select: function (event, ui) {
let brand_id = $("input[name='brand_id']");
let brand_name = $("input[name='brand_name']");
let product_id = $("input[name='product_id']");
let product_name = $("input[name='product_name']");
let serial_number = $("input[name='serial_number']");
brand_id.val(ui.item.brand_id);
brand_name.val(ui.item.brand_name);
product_id.val(ui.item.product_id);
product_name.val(ui.item.product_name);
serial_number.val(ui.item.serial_number);
}
});
The Javascript Code make search when user input at least 3 letters, if only one record match the case, it is auto selected by response:.
The selected: case populate other input field when user select a certain voice into suggestions list.
Here che controller that return suggestions data:
#http.route("/serial_search", type="json",
auth="public", website=True)
def serial_search(self, serial):
"""
Starting from a serial number (portal user input),
serach for the corresponding lot and then search
for product id/name and brand id/name.
Return them to the website form.
"""
serial_domain = [("name", "ilike", serial)]
serial_objs = request.env["stock.production.lot"] \
.sudo().search(serial_domain, limit=10)
if not serial_objs:
return {"fail": True}
suggestions = []
for serial_obj in serial_objs:
serial_vals = {}
serial_vals['data'] = serial_obj.product_id.id
serial_vals['value'] = serial_obj.name
serial_vals['product_id'] = serial_obj.product_id.id
serial_vals['product_name'] = '%s - %s' % (
serial_obj.product_id.default_code, serial_obj.product_id.name)
serial_vals['brand_id'] = serial_obj.product_id.product_brand_id.id
serial_vals['brand_name'] = serial_obj.product_id.product_brand_id.name
serial_vals['serial_number'] = serial_obj.name
suggestions.append(serial_vals)
# make a list of dicts with serial number values
return suggestions

Pass Angular typeahead object result to another function in controller

In this scenario I'm using the ui-bootstrap typeahead to capture an object from an external api. Using the select callback I'm getting that object and have the results set in a separate function within my controller.
The issue is that I want to take those results and send them off to a separate api with a click function I already have set up. My question is how do i get the results of the type-ahead into the click function to post? The user flow is as follows.
<div>
<input type="text" placeholder="Find A Game"
typeahead-on-select="setGames($item)"
ng-model="asyncSelected"
typeahead="test.name for test in getGames($viewValue)"
typeahead-loading="loadingLocations" typeahead-min-length="3"
typeahead-wait-ms="500" typeahead-select-on-blur="true"
typeahead-no-results="noResults">
</div>
<div ng-show="noResults">
No Results Found
</div>
<button ng-disabled="!asyncSelected.length"
ng-click="addtodb(asyncSelected)">Add To Database</button>
As you can see the label is set to the items name and this works fine. When the user selects the name I then use typeahead-on-select="setGames($item)" to send off the entire object to its own funtion. From there I want to take the object and pass it to another function that you can see within the button tags ng-click. I currently have it passing the model, but what I really want is to pass the entire object within $item from the select event. So far my controller looks like this:
angular.module('2o2pNgApp')
.controller('GiantCtrl', function ($scope, $http, TermFactory, $window, SaveFactory) {
$scope.getGames = function(val) {
return $http.jsonp('http://www.example.com/api/search/?resources=game&api_key=s&format=jsonp&limit=5&json_callback=JSON_CALLBACK', {
params: {
query: val
}
}).then(function(response){
return response.data.results.map(function(item){
return item;
});
});
};
$scope.setGames = function (site) {
var newsite = site;
};
$scope.addtodb = function (asyncSelected, newsite) {
TermFactory.get({name: asyncSelected}, function(data){
var results = data.list;
if (results === undefined || results.length === 0) {
SaveFactory.save({vocabulary:'5', name:newsite.name, field_game_id:newsite.id}, function(data) {
$window.alert('All Set, we saved '+asyncSelected+' into our database for you!')
});
} else {
// do stuff
});
}
});
No matter what I do I cant seem to pass the entire $item object into this click function to post all the info i need.
Via New Dev in Comments:
$item is only available locally for typeahead-on-select... you can
either assign it to some model within your controller, or, in fact,
make the model of typeahead to be the item: typeahead="test as
test.name for test in getGames($viewValue)" – New Dev

Having issues tying together basic javascript chat page

I have the skeleton of a chat page but am having issues tying it all together. What I'm trying to do is have messages sent to the server whenever the user clicks send, and also, for the messages shown to update every 3 seconds. Any insights, tips, or general comments would be much appreciated.
Issues right now:
When I fetch, I append the <ul class="messages"></ul> but don't want to reappend messages I've already fetched.
Make sure my chatSend is working correctly but if I run chatSend, then chatFetch, I don't retrieve the message I sent.
var input1 = document.getElementById('input1'), sendbutton = document.getElementById('sendbutton');
function IsEmpty(){
if (input1.value){
sendbutton.removeAttribute('disabled');
} else {
sendbutton.setAttribute('disabled', '');
}
}
input1.onkeyup = IsEmpty;
function chatFetch(){
$.ajax({
url: "https://api.parse.com/1/classes/chats",
dataType: "json",
method: "GET",
success: function(data){
$(".messages").clear();
for(var key in data) {
for(var i in data[key]){
console.log(data[key][i])
$(".messages").append("<li>"+data[key][i].text+"</li>");
}
}
}
})
}
function chatSend(){
$.ajax({
type: "POST",
url: "https://api.parse.com/1/classes/chats",
data: JSON.stringify({text: $('input1.draft').val()}),
success:function(message){
}
})
}
chatFetch();
$("#sendbutton").on('click',chatSend());
This seems like a pretty good project for Knockout.js, especially if you want to make sure you're not re-appending messages you've already sent. Since the library was meant in no small part for that sort of thing, I think it would make sense to leverage it to its full potential. So let's say that your API already takes care of limiting how many messages have come back, searching for the right messages, etc., and focus strictly on the UI. We can start with our Javascript view model of a chat message...
function IM(msg) {
var self = this;
self.username = ko.observable();
self.message = ko.observable();
self.timestamp = ko.observable();
}
This is taking a few liberties and assuming that you get back an IM object which has the name of the user sending the message, and the content, as well as a timestamp for the message. Probably not too far fetched to hope you have access to these data elements, right? Moving on to the large view model encapsulating your IMs...
function vm() {
var self = this;
self.messages = ko.observableArray([]);
self.message = ko.observable(new IM());
self.setup = function () {
self.chatFetch();
self.message().username([user current username] || '');
};
self.chatFetch = function () {
$.getJSON("https://api.parse.com/1/classes/chats", function(results){
for(var key in data) {
// parse your incoming data to get whatever elements you
// can matching the IM view model here then assign it as
// per these examples as closely as possible
var im = new IM();
im.username(data[key][i].username || '');
im.message(data[key][i].message || '');
im.timestamp(data[key][i].message || '');
// the ([JSON data] || '') defaults the property to an
// empty strings so it fails gracefully when no data is
// available to assign to it
self.messages.push(im);
}
});
};
}
All right, so we have out Javascript models which will update the screen via bindings (more on that in a bit) and we're getting and populating data. But how do we update and send IMs? Well, remember that self.message object? We get to use it now.
function vm() {
// ... our setup and initial get code
self.chatSend = function () {
var data = {
'user': self.message().username(),
'text': self.message().message(),
'time': new Date()
};
$.post("https://api.parse.com/1/classes/chats", data, function(result) {
// do whatever you want with the results, if anything
});
// now we update our current messages and load new ones
self.chatFetch();
};
}
All right, so how do we keep track of all of this? Through the magic of bindings. Well, it's not magic, it's pretty intense Javascript inside Knockout.js that listens for changes and the updates the elements accordingly, but you don't have to worry about that. You can just worry about your HTML which should look like this...
<div id="chat">
<ul data-bind="foreach: messages">
<li>
<span data-bind="text: username"></span> :
<span data-bind="text: message"></span> [
<span data-bind="text: timestamp"></span> ]
</li>
</ul>
</div>
<div id="chatInput">
<input data-bind="value: message" type="text" placeholder="message..." />
<button data-bind="click: $root.chatSend()">Send</button>
<div>
Now for the final step to populate your bindings and keep them updated, is to call your view model and its methods...
$(document).ready(function () {
var imVM = new vm();
// perform your initial search and setup
imVM.setup();
// apply the bindings and hook it all together
ko.applyBindings(imVM.messages, $('#chat')[0]);
ko.applyBindings(imVM.message, $('#chatInput')[0]);
// and now update the form every three seconds
setInterval(function() { imVM.chatFetch(); }, 3000);
});
So this should give you a pretty decent start on a chat system in an HTML page. I'll leave the validation, styling, and prettifying as an exercise to the programmer...

Copy word document between document libraries in different subsites (SharePoint)

What is the best (subjective.. I know. Sorry!) method for prompting a user to copy an instance of a document in my library to a library in his own site (on the same site collection, if that matters)? I am an administrator with a few word documents that I create too frequently to set specific content types for. So I have created a library that contains a few word templates for them to copy over (most importantly: metadata included except for the modified/created fields).
I have tried a few javascript/jquery methods that I'd put on the display form with a text box allowing them to enter their library url and how many copies they'd like to make, but that doesn't seem to work as I'd like. What would be the most efficient way of accomplishing this? Using an event handler? If so, is there any way to associate one of these with a custom button on the ribbon (I've only associated these buttons for js functions)?
Example of the javascript function I was trying to use:
function copyItem() {
var itemurl = $("#copyFrom").val();
var dst = $("#copyTo").val();
$().SPServices({
operation: "GetItem",
Url: itemurl,
async: false,
completefunc: function (xData, Status) {
itemstream = $(xData.responseXML).find("Stream").text();
itemfields = "";
$(xData.responseXML).find("FieldInformation").each(function(){
itemfields+=$(this).get(0).xml;
});;
}
});
$().SPServices({
operation: "CopyIntoItems",
SourceUrl: itemurl,
async: false,
DestinationUrls: [dst],
Stream: itemstream,
Fields:itemfields,
completefunc: function (xData, Status) {
var error = $(xData.responseXML).find("CopyResult").first().attr("ErrorCode");
}
}
}
called by:
<label>from:</label><input type="text" value="" id="copyFrom" maxlength="255">
<label>to:</label><input type="text" value="" id="copyTo" maxlength="255">
<input type="button" onclick="copyItem();" value="Copy">
note: I am not entering any values into these text boxes right now as I'm manually entering them into itemurl and dst.
But the console says:
The value of the property 'copyItem' is null or undefined, not a Function object.
It's not recommended to use "async:false". It's better to do an asynchronous call and insert your second SPServices into the first one.
Also a close parenthesis is missing for your second SPServices.
And finally, the "Fields" must be an array (http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems.aspx).
I tried the below code and it worked for me:
var srcurl="http://my.sharepoint.com/aymeric_lab/Shared%20Documents/879258.jpeg";
var desturl="http://my.sharepoint.com/aymeric_lab/Shared%20Documents/879258_copy.jpeg";
$().SPServices({
operation: "GetItem",
Url: srcurl,
completefunc: function (xData, Status) {
var itemstream = $(xData.responseXML).find("Stream").text();
var itemfields = [];
$(xData.responseXML).find("FieldInformation").each(function(){
itemfields.push($(this).get(0).xml);
});
$().SPServices({
operation: "CopyIntoItems",
SourceUrl: srcurl,
DestinationUrls: [ desturl ],
Stream: itemstream,
Fields:itemfields,
completefunc: function (xData, Status) {
}
})
}
});

Categories