firefox extension with native messaging application not working - firefox-addon

I have a native application developed in Java (compiled jar) , the extension basically sends message to the native application with the user input and get response back into a label on to the web page.
The extension is working fine with Chrome but I am not able to execute the same in Firefox 58.0.1(quantum 64 bit).
Error in the browser console.
can not convert null to object
below is the snippet code and the error screenshots.
{
"manifest_version":2,
"name":"Firefox Automation Extension",
"version":"1.0",
"description":"Automation Extensions",
"icons": {
"16": "icons/synergy.png"
},
"browser_action":{
"default_icon": {
"32" : "icons/synergy.png"
},
"default_title": "Native Messaging Application Testing",
"default_popup": "index.html"
},
"background":{
"scripts": ["background.js"]
},
"applications": {
"gecko": {
"id": "webdom#oracle.com",
"strict_min_version": "58.0"
}
},
"content_security_policy":"script-src 'self' 'unsafe-eval'; object-src 'self'",
"permissions": [
"nativeMessaging", "<all_urls>"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"jquery-1.12.2.min.js",
"contentScript.js"
]
}
]
}
/* background.js */
browser.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
console.info("Received %o from %o, frame", msg, sender.tab, sender.frameId);
// As it is registered in registy
var host_name="xxxxxxxxxxxxxxxxxxx";
// Open port (for communication).
var port = browser.runtime.connectNative(host_name);
// Send message to native application.
port.postMessage(msg);
// Listen for response...
port.onMessage.addListener(function (msg) {
// Send data to the content.
browser.tabs.query({ active: true, currentWindow: true }, function (tabs) {
browser.tabs.sendMessage(tabs[0].id, msg, function (response) { });
});
});
port.onDisconnect.addListener(function () {
console.info("Disconnected.");
});
});
/* contentScript.js */
document.addEventListener("send-message-event", function (data) {
var request = data.detail.data;
console.log("content script : ", request);
// Send message to the background script
browser.runtime.sendMessage(request, null);
});
/**
* Listens to the background script and dispatches 'get-message-event'
* to the client when the data is received.
*/
browser.runtime.onMessage.addListener(function (response, sender, sendResponse) {
console.log(response);
// Send response to the front page
var event = new CustomEvent("get-message-event", {
detail: {
data: response
},
bubbles: true,
cancelable: true
});
document.dispatchEvent(event);
});
/* Main.js (script called from a html page )*/
$(document).ready(function () {
var sendMessageBtn = $('#send-message-button');
var inputElem = $('#input-text');
var responseElem = $('#response');
/**
* Send message operation
*/
sendMessageBtn.click(function () {
var request = {};
request.message = inputElem.val();
var event = new CustomEvent("send-message-event", {
detail: {
data: request
},
bubbles: true,
cancelable: true
});
console.log("From Main : ",event.detail.data);
document.dispatchEvent(event);
});
/**
* Get message event listener
*/
document.addEventListener("get-message-event", function (data) {
var responseObject = data.detail.data;
responseElem.text(responseObject.message);
});
});
index.html page
<!DOCTYPE html>
<html>
<head>
<title>Native Messaging</title>
<meta charset="utf-8">
<link rel="stylesheet" href="bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="page-header">
<h2>Native Messaging</h2>
</div>
<div class="form-group">
<label for="input-text">Input message:</label>
<input class="form-control" id='input-text' type='text' value="Test" />
</div>
<button type="button" class="btn btn-block btn-default" id='send-message-button'>Send Message</button>
<hr>
<div class="well well-lg" id='response'>Response from Native app...</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
<!-- jQuery and JS files -->
<script src="jquery-1.12.2.min.js"></script>
<script src="main.js"></script>
</body>
</html>
While clicking on the send Message button I am getting can not convert null to object error.
the code is working fine in Chrome and i am able to get response from the Native application in chrome extension

I think the problem is because you have not registered your native application in regedit in:
HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\NativeMessagingHosts
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mozilla\NativeMessagingHosts
I would put in permission :
"tabs",
"nativeMessaging",
"<all_urls>",
"webNavigation"
to work with your browser.

Related

Electron.js I can't do the Button action

follow my source code, does anyone know more about Electron around here? I'm starting to study now and I'm trying to create an App that will update some files through an FTP, my problem initially I put a button on the acc.html page, but I can't do its action, I've looked for several examples but with none I can do , to work, it doesn't also arrive in the script that is defined inside the acc.html.
renderer.js
// include the ipc module to communicate with main process.
const ipcRenderer = require('electron').ipcRenderer;
console.log("Chamou O Renderer.js");
document.getElementById('buttonBaixarACCCustoms').open = () => {
//ipcRenderer.send('openFile', {})
console.log("Entrou No IPCRender");
ipcRenderer.send("btnclick", arg); // ipcRender.send will pass the information to main process
}
/*
const btnclick = document.getElementById('buttonBaixarACCCustoms');
btnclick.addEventListener('onclick', function () {
console.log("Entrou No IPCRender");
var arg ="secondparam";
//send the info to main process . we can pass any arguments as second param.
ipcRenderer.send("btnclick", arg); // ipcRender.send will pass the information to main process
});
*/
app.js
const {app, BrowserWindow, ipcMain, } = require('electron');
const url = require("url");
const path = require("path");
const ftp = require("basic-ftp");
let appWindow;
function initWindow() {
appWindow = new BrowserWindow({
width: 1000,
height: 800,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
webviewTag: true
}
})
// Electron Build Path
appWindow.loadURL('file://' + __dirname + '/electron-tabs.html');
/*
appWindow.loadURL(
url.format({
pathname: path.join(__dirname, `/dist/index.html`),
protocol: "file:",
slashes: true
})
);
*/
// Initialize the DevTools.
appWindow.webContents.openDevTools();
appWindow.on('ready-to-show', function () {
appWindow.show();
appWindow.focus();
});
appWindow.on('closed', function () {
appWindow = null
})
}
app.on('ready', initWindow)
// Close when all windows are closed.
app.on('window-all-closed', function () {
// On macOS specific close process
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (win === null) {
initWindow();
example();
}
})
example()
async function example() {
console.log("Entrou No Example...");
const client = new ftp.Client()
client.ftp.verbose = true
try {
await client.access({
host: "127.0.0.1",
user: "topgunav",
password: "topgunav",
secure: false
})
debugger;
//console.log(await client.list());
//await client.uploadFrom("README.md", "README_FTP.md")
//await client.downloadTo("README_COPY.md", "README_FTP.md")
}
catch(err) {
console.log(err)
}
client.close()
}
//ipcMain.on will receive the “btnclick” info from renderprocess
ipcMain.on("btnclick", function (event, arg) {
console.log("Chegou Aqui No IPCMain");
//create new window
/*
var newWindow = new BrowserWindow({ width: 450, height: 300, show:
false,webPreferences: {webSecurity: false,plugins:
true,nodeIntegration: false} }); // create a new window
var facebookURL = "https://www.facebook.com"; // loading an external url. We can
load our own another html file , like how we load index.html earlier
newWindow.loadURL(facebookURL);
newWindow.show();
*/
// inform the render process that the assigned task finished. Show a message in html
// event.sender.send in ipcMain will return the reply to renderprocess
//event.sender.send("btnclick-task-finished", "yes");
});
acc.html
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body style="margin:0">
<h1 style="text-align: center;">Sicronização De CarSet's</h1>
<div class="mb-3">
<label for="caminhoACCCustoms" class="form-label">Informe O Caminho Da Pasta Customs</label>
<input type="text" class="form-control form-control-lg" type="text" id="caminhoACCCustoms" placeholder="C:\Users\eders\OneDrive\Documentos\Assetto Corsa Competizione\Customs">
</div>
<select class="form-select form-select-lg mb-3" aria-label=".form-select-lg example">
<option selected>Informe A Temporada Que Deseja Sicronizar</option>
<option value="1">T1</option>
<option value="2">T2</option>
<option value="3">T4</option>
<option value="3">T5</option>
</select>
<button type="button" class="btn btn-primary btn-lg" id="buttonBaixarACCCustoms">Baixar</button>
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
<script src="../../renderer.js"></script>
</html>
electron-tabs.html
<!DOCTYPE html>
<html>
<head>
<title>SuperSync</title>
<link rel="stylesheet" href="./node_modules/electron-tabs/electron-tabs.css">
</head>
<body style="margin:0">
<div class="etabs-tabgroup">
<div class="etabs-tabs"></div>
<div class="etabs-buttons"></div>
</div>
<div class="etabs-views"></div>
</body>
<script src="./renderer.js"></script>
<script>
const TabGroup = require('electron-tabs');
let tabGroup = new TabGroup();
tabGroup.addTab({
title: "Assetto Corsa Competizione",
src: "./src/acc/acc.html",
visible: true,
active: true
});
</script>
Understanding and implementing Inter-Process Communication
can be tricky. You need a good understanding of
the Process Model
and Context Isolation.
In the below code I have greatly simplified your questions code to show only what is required to get a working IPC
process.
The purpose of this preload.js script is to define 'channel names' and the implementation of IPC between the main
process and render process(es).
This preload.js script can be included in all your window creation scripts. IE: webPreferences: { preload: 'preload.js' }.
preload.js (main process)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'buttonClick' // Channel name
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
This preload.js script can be used in your main process and render process(es) as shown below.
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: electronIpcMain.on('channel', (event, data) => { methodName(data); })
*
* Main --> Render
* ---------------
* Main: windowName.webContents.send('channel', data); // Data is optional.
* Render: window.ipcRender.receive('channel', (data) => { methodName(data); });
*
* Render --> Main (Value) --> Render
* ----------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', async (event, data) => {
* return await promiseFunctionName(data)
* .then(() => { return result; })
* });
*/
During window creation make sure to include your preload.js script. Then listen for a message on the 'buttonClick'
channel.
main.js (main process)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
// Prevent garbage collection
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js') // Include the preload.js script
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// Listen for a message on the 'buttonClick' channel
electronIpcMain.on('buttonClick', (event, data) => {
console.log(data); // Testing
})
Lastly, listen for a click event on the button, gather the data and send it via the correct IPC channel (name) to
the main process for processing.
index.html (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<h1>Sicronização De CarSet's</h1>
<label for="textField">Informe O Caminho Da Pasta Customs</label>
<input id="textField" type="text" placeholder="C:\Custom\Path"><br>
<label for="selectField">Informe A Temporada Que Deseja Sicronizar</label>
<select id="selectField">
<option value="1">T1</option>
<option value="2">T2</option>
<option value="3">T3</option>
<option value="4">T4</option>
</select><br>
<button id="button" type="button">Baixar</button>
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
let data = {
textField: document.getElementById('textField').value,
selectField: document.getElementById('selectField').value
}
console.log(data); // Testing
window.ipcRender.send('buttonClick', data);
});
</script>
</html>

Dymanic listview construction visible in jQuery Mobile 1.4.2 transition

I have a Single Page transition from #homepage to #addresses where the page #addresses include a dynamic listview build based in an $.ajax WebApi call.
The problem is that it's visible the construction of the listview when we arrive at the second page, and I want to avoid that, I want the list all build when we land in the #addresses page.
I also have a delay click in the listview in iPhone.
My code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>izigo.mobile</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css">
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
$(document).bind("mobileinit", function ()
{
$.mobile.toolbar.prototype.options.addBackBtn = true;
$.mobile.toolbar.prototype.options.backBtnText = "voltar";
$.mobile.page.prototype.options.domCache = true;
});
</script>
<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>
<script>
/* Pass data with changePage */
$(document).on("pageinit", "#homepage", function ()
{
$(".category").on("click", function ()
{
$.mobile.pageContainer.pagecontainer("change", "#addresses",
{
categoryId: this.id,
transition: "slide"
});
});
});
/* retrieve data and run function to add elements */
$(document).on("pagebeforechange", function (e, data)
{
if (data.toPage[0].id == "addresses")
{
var categoryId = data.options.categoryId;
clearListCategory("#addresses");
buildListCategory("#addresses", categoryId);
}
});
function clearListCategory(page)
{
var $page = $(page);
$("ul", $page).remove();
}
function buildListCategory(page, categoryId)
{
$.ajax({
type: "POST",
url: "http://10.0.0.200/api/Mobile/GetAddresses",
crossDomain: false,
beforeSend: function () { $.mobile.loading('show') },
complete: function () { $.mobile.loading('hide') },
data: { CategoryId: categoryId },
dataType: 'json',
success: function (addresses)
{
showAddresses(page, addresses);
},
error: function () {
console.log("loadList error!");
}
});
}
function showAddresses(page, addresses)
{
var $page = $(page);
var list = $("<ul/>", {
"data-role": "listview"
});
var items = '';
$.each(addresses, function (i, address)
{
items = $("<li>" + address.Name + "</li>");
list.append(items);
});
$(".ui-content", $page).append(list);
$("ul", $page).listview();
}
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- home-page -->
<div data-role="page" id="homepage">
<div data-role="header" data-position="fixed"><h1>mobile</h1></div>
<div class="ui-content" role="main">
<ul data-role="listview" id="categories">
<li>Oficina</li>
<li>Seguro</li>
<li>Reboque</li>
</ul>
</div>
</div>
<!-- page addresses list -->
<div data-role="page" id="addresses">
<div data-role="header" data-position="fixed"><h1>mobile</h1></div>
<div class="ui-content" role="main"></div>
</div>
</body>
</html>
The code you're using, you populate listview on pagebeforechange event, which is triggered before any other page event. You should populate listview before you navigate to target page, using .success or .complete callback.
$.ajax({
type: "POST",
url: "URL",
crossDomain: false,
beforeSend: function () {
$.mobile.loading('show')
},
complete: function () {
$.mobile.loading('hide')
},
data: {
CategoryId: categoryId
},
dataType: 'json',
success: function (addresses) {
showAddresses(page, addresses);
$.mobile.pageContainer.pagecontainer("change", "#addresses");
},
error: function () {
console.log("loadList error!");
}
});
Demo - Code

Openlayers + Require.js + Backbone.js + jQueryMobile -> Tiles not loading

I have set up a project that uses require.js, backbone.js, openlayers (mobile single file build) and jquery mobile.
Now I have some issues displaying the map correctly, because no tiles are loading. I have figured out how to load the openlayers api with the require.js shim parameter:
shim: {
"backbone": {
"deps": [ "underscore", "jquery" ],
"exports": "Backbone"
},
"openlayers": {
"exports": "OpenLayers"
}
}
In the MapView.js file I create a new openlayers map:
define([ "jquery", "backbone", "openlayers" ], function( $, Backbone, OpenLayers ) {
var MapView = Backbone.View.extend( {
// The View Constructor
initialize: function() {
console.log(3);
var mapOptions = {
div: this.el,
maxExtent: new OpenLayers.Bounds(-174,18.4,-63.5,71),
maxResolution: 0.25,
projection: "EPSG:102100",
theme: "/css/theme/default/style.css",
layers: [
new OpenLayers.Layer.OSM("OpenStreetMap", null, {
transitionEffect: 'resize'
})
]};
this.map = new OpenLayers.Map( mapOptions );
},
render: function() {
console.log(4);
}
} );
return MapView;
} );
Now the map works partly. I can see the Zoom Buttons which are added by openlayers at the top-left of the map, but no Tiles are loaded. Firebug told me, that there isn't even a request for the tiles.
At the moment I have no clue whats the problem might be.
For completetion this is my backbone router:
define([ "jquery", "backbone", "../models/Map", "../views/Map" ], function( $, Backbone, MapModel, MapView ) {
var Router = Backbone.Router.extend( {
initialize: function() {
console.log(2);
this.mapView = new MapView( { el: "#mapView" } );
Backbone.history.start();
},
// Backbone.js Routes
routes: {
"": "home",
},
// Home method
home: function() {
console.log(0);
$.mobile.changePage( "#map" , { reverse: false, changeHash: false } );
},
});
return Router;
} );
and the Page html
<!doctype html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="/css/jquerymobile.css" />
<script src="/js/libs/require-min.js" data-main="/js/mobile"></script>
<style>
#mapView {
height: 500px;
width: 500px;
}
</style>
</head>
<body>
<div id="map" data-role="page" data-title="Map">
<div data-role="header">
<h1>Map</h1>
</div><!-- /header -->
<div data-role="content">
<div id="mapView"></div>
</div><!-- /content -->
</div>
</body>
</html>
Any ideas?
I figured it out now. All I had to do is add this.map.zoomToMaxExtent();. For some reason without that the map was not able to calculate the correct visible extent for the tiles.

How to Move code from jsfiddle to local system for testing

This similar to Question https://stackoverflow.com/questions/13693170/changed-version-of-knockout-js
I would like move the code from jsfiddle to local system for testing. The code works for adds, checked, delete. But, what it does not do is load the fake data from within the model.js. I have changed /echo/json. to local url. What else do I need to do? Using latest firefox.
model.js >>>>
$(document).ready(function() {
var fakeData = [{
"title": "Wire the money to Panama",
"isDone": true},
{
"title": "Get hair dye, beard trimmer, dark glasses and passport",
"isDone": false},
{
"title": "Book taxi to airport",
"isDone": false},
{
"title": "Arrange for someone to look after the cat",
"isDone": false}];
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() && !task._destroy });
});
// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.destroy(task) };
self.save = function() {
$.ajax("/ds", {
data: {
json: ko.toJSON({
tasks: this.tasks
})
},
type: "POST",
dataType: 'json',
success: function(result) {
alert(ko.toJSON(result))
}
});
};
//Load initial state from server, convert it to Task instances, then populate self.tasks
$.ajax("/ds", {
data: {
json: ko.toJSON(fakeData)
},
type: "POST",
dataType: 'json',
success: function(data) {
var mappedTasks = $.map(data, function(item) {
return new Task(item);
});
self.tasks(mappedTasks);
}
});
}
ko.applyBindings(new TaskListViewModel());
});
ds.html
<script type="text/javascript" src="static/js/jquery-1.6.3.min.js"></script>
<script type="text/javascript" src="static/js/knockout-2.0.0.js"></script>
<p>
<div class="codeRunner">
<h3>Tasks</h3>
<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
Delete
</li>
</ul>
You have <b data-bind="text: incompleteTasks().length"> </b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
<button data-bind="click: save">Save</button>
</div>
</p>
<script type="text/javascript" src="static/js/model.js" ></script>
The ajax requests in the fiddle are just mock requests to simulate real-world scenarios, they're not really necessary.. you can use that fake data without any ajax requests. For example change these parts:
self.save = function() {
alert(ko.toJSON({tasks: this.tasks}));
};
//Load initial state from server, convert it to Task instances, then populate self.tasks
var mappedTasks = $.map(fakeData, function(item) {
return new Task(item);
});
self.tasks(mappedTasks);
If you want to use ajax requests to get real data, you'll need to post the data in the format required by your own server API (i.e. not with that 'json' field in the data that is used in jsfiddle's json-echo service API)

Issue when submitting form data via JQuery UI Dialog to the server

I have an asp.net mvc app, using JQuery UI dialog. I'm trying to submit form data to the controler action method. I do hit the action method but my object has no data. Do you know why?
From Filter.cshtml
$("#selectUnits").dialog({
autoOpen: false,
title: 'Select Units',
width: 400,
modal: true,
minHeight: 200,
buttons: {
"Cancel": function () {
$(this).dialog("close");
},
"Submit": function () {
$.post('/Data/SetUnitNumbers', $("#frmSelectedUnits").submit(), function (data) {
alert('This worked');
});
}
} // END OF BUTTONS
}); //END OF DIALOG
From Controler...Action Method:
public void SetUnitNumbers(object data)
{
int a = 5;
}
From SelectUnits.cshtml where form 'frmSelectedUnits' lives. Essentially it is a bunch of checkboxes values that I'm trying to send back to the server:
<body>
<form id="frmSelectedUnits" action="/" >
<div id="unitNumberCheckboxes" style=" ">
<div>
#Html.CheckBox("SelectAllUnitNumbers", false)<label for="SelectAllUnitNumbers"><b>Select/Unselect All Units</b></label>
</div>
<div id="unitCheckboxes">
#foreach (var item in Model)
{
<div style="float:left">
#Html.CheckBox("UnitNumbers", false)<label for="UnitNumbers">#item.unit_number.ToString().PadLeft(3, '0') </label>
</div>
}
</div>
</div>
</form>
</body>
jQuery .post is:
$.post(url, data, success-callback-function);
where data is A map or string that is sent to the server with the request.
Calling $("#frmSelectedUnits").submit() probably won't work.
Try:
$.post('/Data/SetUnitNumbers', $("#frmSelectedUnits").serialize(), function (data) {
alert('This worked');
});
jQuery docs on .serialize()

Resources