Anonymous function not working - javascript

I am getting the error "Uncaught TypeError: $.fblogin is not a function" when I call
$.fblogin({
fbId: 'xxxxxxxxxx',
permissions: 'email,user_birthday',
success: function (data) {
console.log('User birthday' + data.birthday + 'and email ' + data.email);
}
});
The function is defined bellow:
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.extend({
/**
* fblogin
* #property {object} options - settings for fblogin plugin.
*
* Required:
* options.fbId {string} - the Facebook app id
*
* Optional:
* options.permissions {string} - a comma seperated list of FB permissions. See http://bit.ly/1plqJSs
* options.fields {string} - a comma seperated list of field ids. See http://bit.ly/1plrevO
* options.success {function} - callback that will be triggered when data is successfully returned from FB.
* options.error {function} - callback that will be triggered by any errors.
*/
fblogin: function (options) {
/**
* Private Props
* #property {object} __ - add private module functions here.
* #property {object} isSdkLoaded - a flag for when the FB SDK has loaded.
* #property {object} isFbInitiated - a flag for when FB.init has been called.
* #property {object} $dfd - stores an instance of jquery Deferred.
*/
var __,
isSdkLoaded,
isFbInitiated,
$dfd;
options = options || {};
isSdkLoaded = false;
isFbInitiated = false;
$dfd = $.Deferred();
// PRIVATE FUNCTIONS
__ = {
init: function () {
// FB ID is required
if (!options.fbId) {
throw new Error('Required option "fbId" is missing!');
}
options.permissions = options.permissions || '';
options.fields = options.fields || '';
options.success = options.success || function(){};
options.error = options.error || function(){};
__.listenForFbAsync();
},
listenForFbAsync: function () {
if (window.fbAsyncInit) {
var notMyFunction = window.fbAsyncInit;
}
// listen for FB SDK load
window.fbAsyncInit = function() {
__.initFB();
isSdkLoaded = true;
if (notMyFunction) { notMyFunction(); }
};
if (isSdkLoaded || window.FB) {
window.fbAsyncInit();
return;
}
},
initFB: function () {
if (!isFbInitiated) {
window.FB.init({
appId : options.fbId,
cookie : true,
xfbml : true,
version : 'v2.0'
});
isFbInitiated = true;
}
$dfd.notify({status: 'init.fblogin'});
},
loginToFB: function () {
window.FB.login(function(response) {
if (response.authResponse) {
$dfd.notify({
status: 'authenticate.fblogin',
data: response
});
} else {
// mimic facebook sdk error format
$dfd.reject({
error: {
message: 'User cancelled login or did not fully authorize.'
}
});
}
}, {
scope: options.permissions,
return_scopes: true
});
},
getFbFields: function (accessToken) {
FB.api('/me', {fields: options.fields}, function(response) {
if (response && !response.error) {
$dfd.resolve(response);
}
else {
$dfd.reject(response);
}
});
}
};
// This monitors the FB login progresssion
// 1. Init FB
// 2. FB.login
// 3. Get user data
$dfd.progress(function (response) {
if( response.status === 'init.fblogin' ) {
__.loginToFB();
} else if( response.status === 'authenticate.fblogin' ) {
__.getFbFields(response.data.authResponse.accessToken);
} else {
dfd.reject();
}
});
// point callbacks at deffereds
$dfd.done(options.success);
$dfd.fail(options.error);
// here we go!
__.init();
return $dfd;
}
});
}));

It seems your jQuery is getting loaded again after the above script. You can check in console or move the script down in the page and verify.

Related

Javascript await for response before returning result JS plugin

I've build a JS plugin that I'm loading into my project. I'm using Gulp 4 to compile everything, and I'm struggling with one of my methods. The method accepts a boolean value of true or false, and if the value of true is specified, then the function that the method calls runs an API request which updates my plugin's options.
However, in the project that listens for the response of the method, it doesn't account for the response of the API request.
Plugin:
(function() {
this.MyPlugin = function() {
/*
** Settings
**
** Default settings of the plugin that we can overwrite later
*/
const INBOUND_CONFIG = {
features: {
settingOne: 'setting one',
settingTwo: 'setting two'
}
}
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(INBOUND_CONFIG, arguments[0]);
}
/*
** Compile Detailed Settings
**
** Compile detailed settings
*/
function compactFeatures (config) {
const tlp_aff_id = buildTlpAffID(
config.features.cpm_id,
config.features.sub_id,
config.brand
)
return {
tlp_aff_id: tlp_aff_id
}
}
/*
** Get inbound options
**
** Get inbound options if we're not on the inbound page so that they're,
** accessible throughout the app
*/
function getSettings (prefersDB = false) {
purgeInboundConfig(false)
let inbound
if (localStorage.getItem('example--inbound')) {
inbound = JSON.parse(encodeAndDecode(localStorage.getItem('example--inbound'), 'decode'))
} else {
inbound = JSON.parse(localStorage.getItem('example--inbound'))
}
// prefers db
if (prefersDB) {
fetchFromDB()
return
}
let features = { ...compare(inbound, INBOUND_CONFIG.features), ...compactFeatures(INBOUND_CONFIG) }
INBOUND_CONFIG.features = validateInboundSettings(features)
}
/*
** Comparison
**
** We need to compare the inbound settings parsed against the default,
** settings that we have. If one from the inbound settings matches a,
** default one, we overwrite it and use the value from the inbound
*/
function compare (inbound, defaults) {
let settings = defaults
if (!inbound) return settings
for (const [key, value] of Object.entries(inbound)) {
for (var option in defaults) {
if (defaults.hasOwnProperty(option)) {
if (key == option) {
settings[key] = convertToOriginalType(value)
continue
}
}
}
}
return settings
}
/*
** Find Affiliate from DB
**
** Find an affiliate from the DB and fetch the appropriate data
**
*/
function fetchFromDB () {
const query = JSON.parse(encodeAndDecode(localStorage.getItem('example--query'), 'decode'))
// construct the data that we need
const data = {
affiliate: query.cpm_id ?? '',
query: query ?? []
}
makeInboundHTTPRequest('POST', `https://example.com/api/affiliate/find`, 5000, JSON.stringify(data), function () {
const res = JSON.parse(this.response.data.response)
INBOUND_CONFIG.features = res.options ?? []
// rerun to get settings
getSettings()
})
}
/*
** HTTP requests
**
** This function will handle HTTP requests made by the plugin to and from,
** the processor.
*/
function makeInboundHTTPRequest (
type = 'GET',
url = '',
timeout = 30000,
payload = null,
callback
) {
const xhr = new XMLHttpRequest()
xhr.open(type, url, true)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.timeout = timeout
xhr.ontimeout = () => {
callback.apply({
response: { error: true, message: `Timeout exceeded ${timeout}ms`, data: null }
})
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.response != null) {
callback.apply({
response: { error: false, message: 'Success', data: xhr }
})
} else {
callback.apply({
response: { error: false, message: 'No data', data: null }
})
}
}
}
xhr.onerror = () => {
callback.apply({
response: { error: true, message: 'Generic error', data: null }
})
}
if (type === 'POST') {
xhr.send(payload)
return
}
xhr.send()
}
/*
** Get Inbound Options
**
** Get Inbound Config
*/
MyPlugin.prototype.getSettings = function(prefersDB = false) {
getSettings(prefersDB)
return INBOUND_CONFIG.features
}
/*
** Extend Defaults
**
** Utility method to extend defaults with user options
*/
function extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
}
/*
** Plugin Loaded
**
** Let the client know that the plugin is working!
*/
window.postMessage('example--inbound-ready', '*')
}());
The above code is incomplete and doesn't contain every function, but purely contains the related one to my question which is:
MyPlugin.prototype.getSettings = function(prefersDB = false) {
getSettings(prefersDB)
return INBOUND_CONFIG.features
}
Now, if I add a setTimeout to this method, then INBOUND_CONFIG.features has the correct returned response when the value of true is passed to the function, otherwise it doesn't
Site
/*
** Define our plugins
**
** Define our plugins that we want to enable
*/
var inbound
const plugins = {
inbound: {
isEnabled: false
}
}
/*
** Enable Plugins
**
** Listen for plugins, if they're included then let's enable them
*/
const eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent'
const eventer = window[eventMethod]
const messageEvent = eventMethod == 'attachEvent' ? 'onmessage' : 'message'
// Listen to message from child window
eventer(messageEvent, function(e) { // eslint-disable-line prefer-arrow-callback
const str = e.data.toString()
if (str == 'myplugin--inbound-ready') {
// Enable the plugin
plugins.inbound.isEnabled = true
// Load Inbound Plugin
if (plugins.inbound.isEnabled) {
mypluginInbound = new MyPlugin()
inbound = mypluginInbound.getSettings(true) <-- this doesn't contain updated api settings
} else {
inbound = ''
}
}
}, false)
How can I make my getSettings method wait for a response, do I add a set timeout to it, or a promise? I can't use async/await in this project for bigger reasons.

Calls within callback do nothing

I am trying to make a call to another function from a callback but it does not do anything even if the callback is executed. What can be?
This is React Native, although in this payment gateway code there is no JSX involved:
var conektaApi = new Conekta();
conektaApi.setPublicKey('key_CWraZrrnBCZ5aFP6FtYNz9w');
conektaApi.createToken({
cardNumber: '4242424242424242',
name: 'Manolo Virolo',
cvc: '111',
expMonth: '11',
expYear: '21',
}, function(data){
this.callAnotherFunction()
//I also tried anonymous function and arrow
// ()=>{ callAnotherFunction}
}, function(){
console.log( 'Error!' );
})
}
In no way am I succeeding in having another function executed in case of success. In github you can find the js code of the Conekta module, which is a very simple code in reality but I can not deduce what is happening or how to fix it.
I think the problem is in the index.js of the dependency of Conekta:
Conekta module js
This contains the index.js of Conekta:
/**
* #providesModule Conekta
*/
'use strict';
// RNConekta
const RNConekta = require('react-native').NativeModules.RNConekta;
const Platform = require('react-native').Platform;
var Conekta = function() {
this.publicKey = false;
};
/**
* Params:
* publicKey: String (Your testing or production Public Key)
*/
Conekta.prototype.setPublicKey = function(publicKey: String) {
this.publicKey = publicKey;
};
/**
* Params:
* info = {
* cardNumber: String
* name: String
* cvc: String
* expMonth: String
* expYear: String
* }
*/
Conekta.prototype.createToken = function(info: Object, success: Function, error:Function) {
info.publicKey = this.publicKey;
RNConekta.createToken(info, function(response){
if ( Platform.OS === 'android' ) {
success( JSON.parse( response ) );
} else {
success( response );
}
}, error);
};
module.exports = Conekta;
I'm not familiar with Conekta but I think you need to specify a parameter for an error too in your function(data) line like this:
function(err, data){
if (err) {
console.error(err);
return;
}
this.callAnotherFunction()
}

Attaching files stopped working octobercms email ajax form

The below setup has worked until it stopped and right now I'm perplexed why.
I've created a contact form with file attachment in OctoberCMS as below
{{ form_ajax('ContactForm::onSend', { files: 'true', flash: 'true', 'data-request-files':true, 'data-request-validate': true }) }}
<input type="hidden" name="handler" value='onSave'>
<fieldset class="form">
<input type="name" name="name" placeholder="Imię i nazwisko" required>
<input type="email" name="email" placeholder="E-mail" required>
<input type="phone" name="phone" placeholder="Telefon">
<input type="text" name="subject" placeholder="Temat" >
<textarea name="theMessage" placeholder="Zapytanie" required style="width: 100%; height: 140px;"></textarea>
<input type="file" name="fileAttachment" id="fileAttachment" class="inputfile" data-multiple-caption="wybrano {count}" /><label for="fileAttachment">wybierz plik </label><span class='attachmentName'></span>
</fieldset>
<button type="submit" class="send" data-attach-loading>Wyślij</button>
</fieldset>
{{ form_close() }}
The component for sending email
<?php namespace Depcore\Parts\Components;
use Cms\Classes\ComponentBase;
use Mail;
use Lang;
use Flash;
use Input;
use Validator;
use ValidationException;
use Redirect;
use System\Models\File;
class ContactForm extends ComponentBase
{
public function componentDetails()
{
return [
'name' => 'depcore.parts::lang.components.contactFormTitle',
'description' => 'depcore.parts::lang.components.contactFormDescription'
];
}
public function defineProperties()
{
return [
'emailTo' => [
'title' => 'depcore.parts::components.emailAddress',
'description' => 'depcore.parts::components.destinationEmailDescription',
'default' => 'zamowienia#kludi.pl',
'validationPattern' => "\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z",
'ValidationMessage' => ''
]
];
}
public function onSend(){
$data = post();
$vars = [
'name' => Input::get('name'),
'subject' => Input::get('subject'),
'phone' => Input::get('phone'),
'theMessage' => Input::get('theMessage'),
'fileAttachment' => Input::file('fileAttachment'),
];
$rules = [
'name' => 'required',
'email' => 'required|email'
];
$validator = Validator::make($data, $rules);
if ($validator->fails())
throw new ValidationException( $validator );
else {
Mail::send('depcore.parts::mail.message', $vars, function( $message ) use ( $vars ) {
// $message->to($this->property('emailTo'));
$message->to('adam#depcore.pl');
if ($vars['fileAttachment']) {
$file = (new File())->fromPost($vars['fileAttachment']);
$message->attach($file['path']);
}
$message->subject($vars['subject']);
Flash::success('Wiadomość została wysłana.');
});
}
}
}
From what I can tell is that the Input::file('fileAttachemnt') is always returning null so I think It could be a problem with the JavaScript framework (?).
This is a weird thing that got me by surprise when working with the project an now Im stuck.
From your code it looks like by mistake you used wrong method
$vars = [
'name' => Input::get('name'),
'subject' => Input::get('subject'),
'phone' => Input::get('phone'),
'theMessage' => Input::get('theMessage'),
'fileAttachment' => Input::get('fileAttachment'), <-- here
];
your code is using this
Input::get('fileAttachemnt');
In Reality it should be this
Input::file('fileAttachemnt');
may be you updated your code and didn't notice that ;)
UPDATE
ok I guess there is some issue with File facade code (new File())
let not use that instead we can directly use file as also you are not saving that file so,
can you replace your code and check it once
$file = (new File())->fromPost($vars['fileAttachment']);
$message->attach($file['path']);
TO
$file = $vars['fileAttachment'];
$pathToFile = $file->getPathname();
$fileName = $file->getClientOriginalName();
$mime = $file->getMimeType()
$message->attach($pathToFile, ['as' => $fileName, 'mime' => $mime]);
then check it, it should work.
MORE UPDATE
I added modified version of ajax framework (added js snippet), code is taken from October cms official git repo, and just removed some part of it so it can override existing code without conflicts.
I would suggest, take this code and create ajax-fw-override.js file then include file on your page or just duplicate layout and add it at very bottom, any how it should come after October default ajax {% framework %}, so it can override its Request.
This is not good solution but considering that you can't update your cms version we can use this. (also by making duplicate layout we make sure it won't affect anywhere else).
I tested it on your site using console and it worked. so just check it out and let me know.
+ function($) {
"use strict";
var Request = function(element, handler, options) {
var $el = this.$el = $(element);
this.options = options || {};
/*
* Validate handler name
*/
if (handler === undefined) {
throw new Error('The request handler name is not specified.')
}
if (!handler.match(/^(?:\w+\:{2})?on*/)) {
throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')
}
/*
* Prepare the options and execute the request
*/
var $form = options.form ? $(options.form) : $el.closest('form'),
$triggerEl = !!$form.length ? $form : $el,
context = {
handler: handler,
options: options
}
$el.trigger('ajaxSetup', [context])
var _event = jQuery.Event('oc.beforeRequest')
$triggerEl.trigger(_event, context)
if (_event.isDefaultPrevented()) return
var loading = options.loading !== undefined ? options.loading : null,
isRedirect = options.redirect !== undefined && options.redirect.length,
useFlash = options.flash !== undefined,
useFiles = options.files !== undefined
if (useFiles && typeof FormData === 'undefined') {
console.warn('This browser does not support file uploads via FormData')
useFiles = false
}
if ($.type(loading) == 'string') {
loading = $(loading)
}
/*
* Request headers
*/
var requestHeaders = {
'X-OCTOBER-REQUEST-HANDLER': handler,
'X-OCTOBER-REQUEST-PARTIALS': this.extractPartials(options.update)
}
if (useFlash) {
requestHeaders['X-OCTOBER-REQUEST-FLASH'] = 1
}
/*
* Request data
*/
var requestData,
inputName,
data = {}
$.each($el.parents('[data-request-data]').toArray().reverse(), function extendRequest() {
$.extend(data, paramToObj('data-request-data', $(this).data('request-data')))
})
if ($el.is(':input') && !$form.length) {
inputName = $el.attr('name')
if (inputName !== undefined && options.data[inputName] === undefined) {
options.data[inputName] = $el.val()
}
}
if (options.data !== undefined && !$.isEmptyObject(options.data)) {
$.extend(data, options.data)
}
if (useFiles) {
requestData = new FormData($form.length ? $form.get(0) : null)
if ($el.is(':file') && inputName) {
$.each($el.prop('files'), function() {
requestData.append(inputName, this)
})
delete data[inputName]
}
$.each(data, function(key) {
requestData.append(key, this)
})
} else {
requestData = [$form.serialize(), $.param(data)].filter(Boolean).join('&')
}
/*
* Request options
*/
var requestOptions = {
url: window.location.href,
crossDomain: false,
context: context,
headers: requestHeaders,
success: function(data, textStatus, jqXHR) {
/*
* Halt here if beforeUpdate() or data-request-before-update returns false
*/
if (this.options.beforeUpdate.apply(this, [data, textStatus, jqXHR]) === false) return
if (options.evalBeforeUpdate && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalBeforeUpdate + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))') === false) return
/*
* Trigger 'ajaxBeforeUpdate' on the form, halt if event.preventDefault() is called
*/
var _event = jQuery.Event('ajaxBeforeUpdate')
$triggerEl.trigger(_event, [context, data, textStatus, jqXHR])
if (_event.isDefaultPrevented()) return
if (useFlash && data['X_OCTOBER_FLASH_MESSAGES']) {
$.each(data['X_OCTOBER_FLASH_MESSAGES'], function(type, message) {
requestOptions.handleFlashMessage(message, type)
})
}
/*
* Proceed with the update process
*/
var updatePromise = requestOptions.handleUpdateResponse(data, textStatus, jqXHR)
updatePromise.done(function() {
$triggerEl.trigger('ajaxSuccess', [context, data, textStatus, jqXHR])
options.evalSuccess && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalSuccess + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
})
return updatePromise
},
error: function(jqXHR, textStatus, errorThrown) {
var errorMsg,
updatePromise = $.Deferred()
if ((window.ocUnloading !== undefined && window.ocUnloading) || errorThrown == 'abort')
return
/*
* Disable redirects
*/
isRedirect = false
options.redirect = null
/*
* Error 406 is a "smart error" that returns response object that is
* processed in the same fashion as a successful response.
*/
if (jqXHR.status == 406 && jqXHR.responseJSON) {
errorMsg = jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE']
updatePromise = requestOptions.handleUpdateResponse(jqXHR.responseJSON, textStatus, jqXHR)
}
/*
* Standard error with standard response text
*/
else {
errorMsg = jqXHR.responseText ? jqXHR.responseText : jqXHR.statusText
updatePromise.resolve()
}
updatePromise.done(function() {
$el.data('error-message', errorMsg)
/*
* Trigger 'ajaxError' on the form, halt if event.preventDefault() is called
*/
var _event = jQuery.Event('ajaxError')
$triggerEl.trigger(_event, [context, errorMsg, textStatus, jqXHR])
if (_event.isDefaultPrevented()) return
/*
* Halt here if the data-request-error attribute returns false
*/
if (options.evalError && eval('(function($el, context, errorMsg, textStatus, jqXHR) {' + options.evalError + '}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))') === false)
return
requestOptions.handleErrorMessage(errorMsg)
})
return updatePromise
},
complete: function(data, textStatus, jqXHR) {
$triggerEl.trigger('ajaxComplete', [context, data, textStatus, jqXHR])
options.evalComplete && eval('(function($el, context, data, textStatus, jqXHR) {' + options.evalComplete + '}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
},
/*
* Custom function, requests confirmation from the user
*/
handleConfirmMessage: function(message) {
var _event = jQuery.Event('ajaxConfirmMessage')
_event.promise = $.Deferred()
if ($(window).triggerHandler(_event, [message]) !== undefined) {
_event.promise.done(function() {
options.confirm = null
new Request(element, handler, options)
})
return false
}
if (_event.isDefaultPrevented()) return
if (message) return confirm(message)
},
/*
* Custom function, display an error message to the user
*/
handleErrorMessage: function(message) {
var _event = jQuery.Event('ajaxErrorMessage')
$(window).trigger(_event, [message])
if (_event.isDefaultPrevented()) return
if (message) alert(message)
},
/*
* Custom function, focus fields with errors
*/
handleValidationMessage: function(message, fields) {
$triggerEl.trigger('ajaxValidation', [context, message, fields])
var isFirstInvalidField = true
$.each(fields, function focusErrorField(fieldName, fieldMessages) {
fieldName = fieldName.replace(/\.(\w+)/g, '[$1]')
var fieldElement = $form.find('[name="' + fieldName + '"], [name="' + fieldName + '[]"], [name$="[' + fieldName + ']"], [name$="[' + fieldName + '][]"]').filter(':enabled').first()
if (fieldElement.length > 0) {
var _event = jQuery.Event('ajaxInvalidField')
$(window).trigger(_event, [fieldElement.get(0), fieldName, fieldMessages, isFirstInvalidField])
if (isFirstInvalidField) {
if (!_event.isDefaultPrevented()) fieldElement.focus()
isFirstInvalidField = false
}
}
})
},
/*
* Custom function, display a flash message to the user
*/
handleFlashMessage: function(message, type) {},
/*
* Custom function, redirect the browser to another location
*/
handleRedirectResponse: function(url) {
window.location.href = url
},
/*
* Custom function, handle any application specific response values
* Using a promisary object here in case injected assets need time to load
*/
handleUpdateResponse: function(data, textStatus, jqXHR) {
/*
* Update partials and finish request
*/
var updatePromise = $.Deferred().done(function() {
for (var partial in data) {
/*
* If a partial has been supplied on the client side that matches the server supplied key, look up
* it's selector and use that. If not, we assume it is an explicit selector reference.
*/
var selector = (options.update[partial]) ? options.update[partial] : partial
if ($.type(selector) == 'string' && selector.charAt(0) == '#') {
$(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
} else if ($.type(selector) == 'string' && selector.charAt(0) == '^') {
$(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
} else {
$(selector).trigger('ajaxBeforeReplace')
$(selector).html(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
}
}
/*
* Wait for .html() method to finish rendering from partial updates
*/
setTimeout(function() {
$(window)
.trigger('ajaxUpdateComplete', [context, data, textStatus, jqXHR])
.trigger('resize')
}, 0)
})
/*
* Handle redirect
*/
if (data['X_OCTOBER_REDIRECT']) {
options.redirect = data['X_OCTOBER_REDIRECT']
isRedirect = true
}
if (isRedirect) {
requestOptions.handleRedirectResponse(options.redirect)
}
/*
* Handle validation
*/
if (data['X_OCTOBER_ERROR_FIELDS']) {
requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'], data['X_OCTOBER_ERROR_FIELDS'])
}
/*
* Handle asset injection
*/
if (data['X_OCTOBER_ASSETS']) {
assetManager.load(data['X_OCTOBER_ASSETS'], $.proxy(updatePromise.resolve, updatePromise))
} else {
updatePromise.resolve()
}
return updatePromise
}
}
if (useFiles) {
requestOptions.processData = requestOptions.contentType = false
}
/*
* Allow default business logic to be called from user functions
*/
context.success = requestOptions.success
context.error = requestOptions.error
context.complete = requestOptions.complete
requestOptions = $.extend(requestOptions, options)
requestOptions.data = requestData
/*
* Initiate request
*/
if (options.confirm && !requestOptions.handleConfirmMessage(options.confirm)) {
return
}
if (loading) loading.show()
$(window).trigger('ajaxBeforeSend', [context])
$el.trigger('ajaxPromise', [context])
return $.ajax(requestOptions)
.fail(function(jqXHR, textStatus, errorThrown) {
if (!isRedirect) {
$el.trigger('ajaxFail', [context, textStatus, jqXHR])
}
if (loading) loading.hide()
})
.done(function(data, textStatus, jqXHR) {
if (!isRedirect) {
$el.trigger('ajaxDone', [context, data, textStatus, jqXHR])
}
if (loading) loading.hide()
})
.always(function(dataOrXhr, textStatus, xhrOrError) {
$el.trigger('ajaxAlways', [context, dataOrXhr, textStatus, xhrOrError])
})
}
Request.DEFAULTS = {
update: {},
type: 'POST',
beforeUpdate: function(data, textStatus, jqXHR) {},
evalBeforeUpdate: null,
evalSuccess: null,
evalError: null,
evalComplete: null
}
/*
* Internal function, build a string of partials and their update elements.
*/
Request.prototype.extractPartials = function(update) {
var result = []
for (var partial in update)
result.push(partial)
return result.join('&')
}
// REQUEST PLUGIN DEFINITION
// ============================
var old = $.fn.request
$.fn.request = function(handler, option) {
var args = arguments
var $this = $(this).first()
var data = {
evalBeforeUpdate: $this.data('request-before-update'),
evalSuccess: $this.data('request-success'),
evalError: $this.data('request-error'),
evalComplete: $this.data('request-complete'),
confirm: $this.data('request-confirm'),
redirect: $this.data('request-redirect'),
loading: $this.data('request-loading'),
flash: $this.data('request-flash'),
files: $this.data('request-files'),
form: $this.data('request-form'),
update: paramToObj('data-request-update', $this.data('request-update')),
data: paramToObj('data-request-data', $this.data('request-data'))
}
if (!handler) handler = $this.data('request')
var options = $.extend(true, {}, Request.DEFAULTS, data, typeof option == 'object' && option)
return new Request($this, handler, options)
}
$.fn.request.Constructor = Request
$.request = function(handler, option) {
return $(document).request(handler, option)
}
// REQUEST NO CONFLICT
// =================
$.fn.request.noConflict = function() {
$.fn.request = old
return this
}
// REQUEST DATA-API
// ==============
function paramToObj(name, value) {
if (value === undefined) value = ''
if (typeof value == 'object') return value
try {
return JSON.parse(JSON.stringify(eval("({" + value + "})")))
} catch (e) {
throw new Error('Error parsing the ' + name + ' attribute value. ' + e)
}
}
}(window.jQuery);

What is wrong with my Angularjs service that I get an $injector error?

I am trying to add a service to eliminate some code that I have been repeating through my app.
The service:
/* --------------------------------------------------------------
---------- FUNCTIONS FOR PAGE ALERTS THROUGHOUT Project-------
---------------------------------------------------------------*/
angular.module('app').service('PageAlertService', function () {
this.setAlert = function() {
console.log("In setAlert");
if (localStorage.getItem("Success")) {
var alertObj = {
alert: "Success",
alertMessage: localStorage.getItem("Success")
};
} else if (localStorage.getItem("Error"){
var alertObj = {
alert: "Error",
alertMessage: localStorage.getItem("Error")
};
};
return alertObj;
};
this.errorStatusCheck = function(error, successString) {
if (error.status = -1) {
localStorage.setItem("Success", successString);
} else {
localStorage.setItem("Error", "Error occured: " + error.status + error.statusText);
};
};
});
but whenever I try to add it to any of my controllers I'd like to use it in it breaks my angular web app and gives me the
Error: $injector:unpr
Unknown Provider
Here is my app.js:
var app = angular.module('app',
[
'JobCtrl',
'JobSvc',
'WebsiteCtrl',
'WebsiteSvc',
'myClientCtrl',
'ClientSvc',
'MediaCompanyCtrl',
'MediaCompanySvc',
'PageAlertSvc',
'ui.bootstrap',
'ui.bootstrap.tpls'
]
);
Here is my controller:
/* --------------------------------------------------
-------- Media Jobs Controller ----------------------
--------------------------------------------------- */
angular.module('app', ['ui.bootstrap', 'ui.bootstrap.tpls'])
.controller('JobCtrl',
[
'JobService',
'WebsiteService',
'MediaCompanyService',
'ProductService',
'$scope',
'$uibModal',
'PageAlertService',
function (JobService, WebsiteService, MediaCompanyService,
ProductService, $scope, $uibModal, $uibModalInstance, PageAlertService)
{
/* ------------------------------------
--------- Variables -----------------
-------------------------------------*/
$scope.mediaCompanies = {};
$scope.websites = {};
$scope.products = [];
$scope.selectedProducts = [];
$scope.isSelected = false;
$scope.new = {
Job: {}
};
/* ----------------------------------------------------------------
--- INITIALIZE LISTS OF JOBS, WEBSITES, COMPANIES, AND PRODUCTS ---
------------------------------------------------------------------*/
/* Get Jobs Initialization */
function getJobs() {
JobService.getJobs()
.then(
function (data) {
$scope.total_count = data.JobCount;
$scope.model = data.mediaJobList;
},
function (errResponse) {
console.log("Error while getting jobs");
});
};
getJobs();
/* Get Websites Initialization */
function getWebsites() {
WebsiteService.getWebsites()
.then(
function (data) {
$scope.websites = data;
},
function (errResponse) {
console.log(errResponse);
});
};
getWebsites();
/* Get Companies Initialization */
$scope.getCompanies = function () {
MediaCompanyService.getCompanies()
.then(
function (data) {
$scope.mediaCompanies = data;
},
function (errResponse) {
console.log(errResponse);
});
};
$scope.getCompanies();
/* Get Products -- passing website id*/
$scope.getProducts = function (webid) {
ProductService.getProducts(webid)
.then(
function (data) {
$scope.selectedProducts = data.MediaProductList;
},
function (errResponse) {
console.log(errResponse);
});
};
/* ----------------------------------------------------------------
----------- STILL NEED TO FIGURE OUT WHAT TO DO WITH YOU ----------
------------------------------------------------------------------*/
///* Shows Success and Error Alerts - Maybe make into a directive or
// Service? */
//if (localStorage.getItem("Success")) {
// $scope.alert = "Success";
// $scope.alertMessage = localStorage.getItem("Success");
// localStorage.clear();
//} else if (localStorage.getItem("Error") && localStorage.getItem("Error") !== null) {
// //sometimes get errors even when adding, deleting, updating is successful
// $scope.alert = "Error";
// $scope.alertMessage = localStorage.getItem("Error");
// localStorage.clear();
//};
if (localStorage.getItem("Success") != null || localStorage.getItem("Error") != null) {
console.log("I'm In")
var alert = {};
alert = PageAlertService.setAlert();
//$scope.alert = alert.alert;
//$scope.alertMessage = alert.alertMessage;
localStorage.clear();
}
/* -----------------------------------
------ JOB CRUD FUNCTIONS ----------
-------------------------------------*/
/* Add Job - Also Adds Products to Database */
$scope.addJob = function () {
var successString = "Added Job Succesfully!";
JobService.addJob($scope.new.Job).then(
function (success) {
localStorage.setItem("Success", successString);
},
function (error) {
//if (error.status = -1 && error.status !== 500) {
// localStorage.setItem("Success", successString);
//} else {
// localStorage.setItem("Error", "Error while adding Job! " + error.status + ":" + error.statusText);
//}
PageAlertService.errorStatusCheck(error, successString);
});
//adds products after adding job
addProducts();
location.reload();
}
/* Update Job -- Also Updates Products in Database */
$scope.updateJob = function (job) {
var successString = "Updated Job Succesfully!";
JobService.updateJob(job).then(
function (success) {
localStorage.setItem("Success", successString);
},
function (error) {
//if (error.status = -1 && error.status !== 500) {
// localStorage.setItem("Success", successString);
//} else {
// localStorage.setItem("Error", "Error while updating job! " + error.status + ":" + error.statusText);
//}
PageAlertService.errorStatusCheck(error, successString);
}
);
updateProducts();
location.reload();
}
/* Delete Job */
$scope.deleteJob = function (job) {
var successString = "Deleted Job Succesfully!";
var indx = $scope.model.indexOf(job);
JobService.deleteJob(job.Id).then(
function (success) {
localStorage.setItem("Success", successString);
},
function (error) {
//if (error.status = -1 && error.status !== 500) {
// localStorage.setItem("Success", successString);
//} else {
// localStorage.setItem("Error", "Error occured while deleting job! " + error.status + ":" + error.statusText);
//}
PageAlertService.errorStatusCheck(error, successString);
}
);
location.reload();
}
/* Run Job */
$scope.runJob = function (id, d1, d2) {
$scope.runButtonText = "Running";
//format Date
var date1 = $scope.FormatDate(d1);
var date2 = $scope.FormatDate(d2);
JobService.runJob(id, date1, date2).then(
function (success) {
$scope.runButtonText = "Finished";
},
function (error) {
if (error.status = -1 && error.status !== 500) {
$scope.runButtonText = "Finished";
} else {
$scope.runButtonText = "Error Occured";
console.log(error);
}
});
}
/* ----------------------------------------------------
---------- PRODUCT CRUD FUNCTIONS ---------------------
------------------------------------------------------*/
var addProducts = function () {
ProductService.addOrUpdate($scope.products).then(
function (response) {
console.log(response);
},
function (err) {
console.log(err);
});
};
var updateProducts = function () {
ProductService.addOrUpdate($scope.selectedProducts).then(
function (response) {
console.log(response);
},
function (err) {
console.log(err);
});
};
var deleteProducts = function (product) {
ProductService.deleteProduct(id).then(
function (response) {
console.log(response);
},
function (err) {
console.log(err);
});
};
/* ----------------------------------------------
--------- Code to Manipulate View Model --------
----------------------------------------------*/
/* Toggles Active Toggle Button */
$scope.updateActive = function (job) {
job.Active = !job.Active;
setTimeout(function () {
}, 500);
this.updateJob(job);
}
/* Selects Job and and Gets Product List */
$scope.selectJob = function (job) {
$scope.isSelected = true;
$scope.goToJobSection = false;
$scope.goToEditSection = true;
$scope.selectedJob = {}
$scope.selectedJob = job;
//selects product list by webid
var websiteId = $scope.selectedJob.WebsiteId;
$scope.getProducts(websiteId);
}
/* Onclick Event to stop people from
adding products to database with different
website ids*/
$scope.remProdOnClick = function () {
var newList = [];
if ($scope.goToEditSection == false) {
$scope.products = [];
}
}
/* ----------------------------------------------------------
--- MODAL -- May need to bring this out into a Directive ----
-----------------------------------------------------------*/
/* Shows Modal */
$scope.showModal = function (action, obj) {
$scope.$modalInstance = $uibModal.open({
scope: $scope,
inputs: {
title: action + " Job"
},
restrict: "E",
templateUrl: 'app/modal/JobModals/modal' + action + 'Template.html',
controller: "JobCtrl",
backdrop: 'static',
keyboard: false
});
}
/* Exits Modal */
$scope.exitModal = function () {
$scope.$modalInstance.dismiss('cancel');
};
}]);
I cannot seem to figure out why this is occurring. All my other services are working perfectly.
Thanks!
On your controller declaration, you inject 7 dependencies, but you have 8 as arguments, you are either forgetting to inject one dependency or to delete one argument.
angular.module('app', ['ui.bootstrap', 'ui.bootstrap.tpls'])
.controller('JobCtrl',
[
'JobService',
'WebsiteService',
'MediaCompanyService',
'ProductService',
'$scope',
// missing dependency here
'$uibModal',
'PageAlertService',
function (JobService, WebsiteService, MediaCompanyService,
ProductService, $scope, $uibModal,
$uibModalInstance // or extra dependency here
, PageAlertService)
{
...
}
I tried multiple solutions but the only thing that seemed to work was by putting my service into the folder with all my other services. Once it was moved I no longer got the $injector error I was talking about above.
/MainProject
-/app
-/Common
-/Controllers
JobCtrl.js
OtherCtrl.js
-/Services
JobSvc.js
PageAlertSvc.js
OtherSvs.js
-/Modal
-/Templates
-/Vendor
app.js
As you can see instead of putting the PageAlertSvc.js in Common I had to put it in the Services folder.
In your controller, you should not need to redefine your module (with its associated dependencies) since it is already defined by app.js. Perhaps try attaching your controller to the existing module.
angular
.module('app')
.controller('JobCtrl', ...
Speaking of app.js, you should not need to inject any of your components/controllers/services since they will be programatically attached later.
angular.module('app', ['ui.bootstrap', 'ui.bootstrap.tpls']);

Manage subscriptions in ui routes with angular meteor

I'm currently building an application with meteor and angularJS using angular-meteor. I'm currently asking myself, how to properly handle subscriptions. My current approach is to:
resolve a route when each dependent subscription is ready
make sure that previous subscriptions on that publication are stopped
Is there a more performant way of doing this?
profileRoutes.js:
function profileRoutes($stateProvider, ResolverProvider) {
$stateProvider
.state('user.profile', {
url: '/:username/profile',
resolve: _.extend(
{
$title: ['$stateParams', function($sp) {
return $sp.username + "'s Profil";
}]
},
ResolverProvider.waitForMedia(),
ResolverProvider.waitForUsers()
),
abstract: true,
views: {
'main': {
controller: 'UserProfileController',
templateUrl: 'client/components/users/profile.html'
}
}
});
}
angular
.module('myApp')
.config(profileRoutes);
resolver.js
function ResolverProvider() {
/**
* _stopIfSubscribed
*
* Checks if a subscription for that publication is already present and stops it.
* #param publicationName
* #private
*/
function _stopIfSubscribed(publicationName) {
_.forEach(_.get(Meteor, 'default_connection._subscriptions'), (handle) => {
if(_.get(handle, 'name') === publicationName && handle.stop) {
handle.stop();
}
});
}
/**
* waitForUsers
*
* Returns resolvers for waiting on my own and all other users
* Does not require a user
* #returns {{meSubscription: *[], usersSubscription: *[]}}
*/
this.waitForUsers = () => {
return {
"meSubscription": ['$meteor', function ($meteor) {
return $meteor.waitForUser();
}],
"usersSubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('allUsers');
return $meteor.subscribe('allUsers');
}]
};
};
/**
* waitForMedia
*
* Returns resolvers for waiting on galleries and media
* #returns {{mediaSubscription: *[], gallerySubscription: *[]}}
*/
this.waitForMedia = () => {
return {
"mediaSubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('media');
return $meteor.subscribe('media');
}],
"gallerySubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('galleries');
return $meteor.subscribe('galleries');
}]
};
};
}

Categories