knockout durandal this... not a funtion - javascript

I have this code:
define(['plugins/dialog', 'knockout', 'backend', 'durandal/app', 'datepicker', 'datepicker_ko'], function (dialog, ko, backend, app, datepicker, datepicker_ko) {
var ApplicationForm = function(config) {
this.config = ko.observableArray(config);
};
ApplicationForm.prototype.submit = function() {
backend.setFormConfig(this.config()).then(function(response){
dialog.close(this);
});
};
ApplicationForm.show = function(config){
return dialog.show(new ApplicationForm(config));
};
return ApplicationForm;
});
congig in the mainfile main.js:
requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'validation_ko': '../lib/knockout/knockout-validation',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1',
'underscore': '../lib/underscore/underscore-min',
'datepicker': '../lib/datepicker/bootstrap-datepicker',
'datepicker_ko': '../lib/datepicker/datepicker_ko'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
And my Problem is, that I get the error:
TypeError: this.config is not a function
I do this many times in my project ans with observables works it fine but not with observableArrays. What do I wrong?

define(['plugins/dialog',
'knockout',
'backend',
'durandal/app',
'datepicker',
'datepicker_ko'], function (dialog, ko, backend, app, datepicker, datepicker_ko) {
var config = ko.observableArray([]);
var submit = function(){
var request = config();
backend.setFormConfig(request).then(function(response){
dialog.close(viewmodel);
});
}
var show = function(config){
dialog.show(viewmodel, config);
}
var activate = function(config){
config(config);
}
var viewmodel =
{
config: config,
submit: submit,
show: show,
activate: activate
};
return viewmodel;});

Related

React-router undefined after concatenation

I've set up an app with react using react-router for routing and are having issues bundling it all.
I'm trying to build/bundle all the js files using gulp-requirejs. But somehow the shim is not included, or the react-router is just ignored. Whatever the problem is, I just end up with an error in the browser console saying Uncaught Error: app missing react-router
I'm including the most important code, feel free to ask if something doesn't make sense.
gulpfile.js
Almond.js is there to replace requirejs
var gulp = require('gulp'),
uglify = require('gulp-uglify'),
rjs = require('gulp-requirejs'),
gulp.task('requirejsBuild', function() {
rjs({
baseUrl: './app/resources/js/',
out: 'app.min.js',
paths: {
'react': '../bower_components/react/react-with-addons',
'react-router': '../bower_components/react-router/dist/react-router',
'react-shim': 'react-shim',
'jquery': '../bower_components/jquery/dist/jquery'
},
shim: {
'react-shim': {
exports: 'React'
},
'react-router': {
deps: ['react-shim']
}
},
deps: ['jquery', 'react-router'],
include: ['init'],
name: '../bower_components/almond/almond'
})
.pipe(uglify()).pipe(gulp.dest('./app/resources/js/'));
});
init.js
require.config({
baseUrl: '/resources/js/',
deps: ['jquery'],
paths: {
'react': '../bower_components/react/react-with-addons',
'react-router': '../bower_components/react-router/dist/react-router',
'react-shim': 'react-shim',
'jquery': '../bower_components/jquery/dist/jquery'
},
shim: {
'react-shim': {
exports: 'React'
},
'react-router': {
deps: ['react-shim']
}
}
});
require(['react', 'app'], function(React, App) {
var app = new App();
app.init();
});
app.js
define([
'react',
'react-router',
], function(
React,
Router,
){
var Route = Router.Route;
var RouteHandler = Router.RouteHandler;
var DefaultRoute = Router.DefaultRoute;
/**
* Wrapper for it all
*
* #type {*|Function}
*/
var Wrapper = React.createClass({displayName: "Wrapper",
mixins: [Router.State],
render: function() {
return (
React.createElement(RouteHandler, null)
);
}
});
var routes = (
React.createElement(Route, {handler: Wrapper, path: "/"}, null)
);
var App = function(){};
App.prototype.init = function () {
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(React.createElement(Handler, null), document.getElementById('content'));
});
};
return App;
}
);
index.html
Mainly containing a script tag
After build you have to manually swap the src with app.min.js
<script data-main="/resources/js/init" src="/resources/bower_components/requirejs/require.js"></script>

How use Jquery-file-upload with backbone.js & require.js

I have an backbone.js application who work with require.js and i want implement this following jquery plugin:
https://github.com/blueimp/jQuery-File-Upload
I have following this processus:
https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin
If anybody can send me an example of backbone app work with this plugin or can help me with other recommandations.
Before you can read my code:
Require.js config :
require.config({
paths: {
'jquery' : 'common/vendors/jquery_2.1.0',
'underscore' : 'common/vendors/underscore_1.6.0',
'backbone' : 'common/vendors/backbone_1.1.2',
'layoutmanager' : 'common/vendors/backbone.layoutmanager_0.9.5',
'jquery.iframe-transport' : 'common/vendors/jquery.iframe.transport_1.0',
'jquery.ui.widget' : 'common/vendors/jquery.ui.widget_1.10.4',
'jquery.fileupload.ui' : 'common/vendors/jquery_fileupload/jquery.fileupload.ui_9.6.0',
'jquery.fileupload' : 'common/vendors/jquery_fileupload/jquery.fileupload_5.40.3'
},
shim: {
'jquery': {
exports: '$'
},
'underscore': {
exports: '_'
},
'backbone' : {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
'layoutmanager' : {
deps: ["backbone"]
}
}
});
My Backbone View :
var define, selector, console;
define([
'jquery',
'underscore',
'backbone',
'layoutmanager',
'../../../../common/models/global/model_picture',
'jquery.ui.widget',
'jquery.iframe-transport',
'jquery.fileupload'
],
function (
$,
_,
Backbone,
LayoutManager,
PictureModel
) {
"use strict";
return Backbone.Layout.extend({
__class__ : "adPostPictureRow",
initialize: function () {
this.template = _.template($('#adpost_picture_row_template').html());
},
events: {
"change .adpost_picture_input_file" : "handleImageUpload"
},
handleImageUpload: function () {
selector = this.$('.adpost_picture_input_file')[0];
this.uploadProgress = 0;
this.model = new PictureModel({ files : selector.files[0] });
var test = $('#adpost_picture_fileupload', this.el).fileupload({
dataType: 'json',
autoUpload: true,
singleFileUploads: true,
url: '../upload/adpost/img',
done: function (data) {
console.log('upload done');
_.each(data.result, function (index, file) {
console.log(file.name);
});
},
add: function () {
// How can access to this function for see the console.log result
console.log('test upload ');
}
});
console.log(test);
}
});
});
Thanks
I'm using this plugin in my backbone Apps.
It works for me using the Jquery plugin inside my render method. Here a sample of my code.
Html File.
<form id="Anything" action="the api url" method='post' encrtype="multipart/form-data">
<input type='file'/ accept='.txt'>
</form>
Backbone View
render: function(){
this.$el.html(this.template);
$("#Anything").fileupload({
dataType:'json',
add : this.AddFile,
fail: this.AddFileFail
});
AddFile : function(data){
return data.submit();
}
}

Backbone.js - Uncaught TypeError: Cannot call method 'receivedEvent' of undefined

I'm using backbone.js for my project. I got this error when run the project on browser.
Uncaught TypeError: Cannot call method 'receivedEvent' of undefined
My code
define(['jquery', 'underscore', 'backbone', 'model/username/usernameModel', 'text!modules/home/homeViewTemplate.html'], function($, _, Backbone, usernameModel, homeViewTemplate) {
var HomeView = Backbone.View.extend({
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicity call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
},
events: {
"click #nextButton": "next",
"click #resetButton": "resetPassword"
},
next: function(event) {
window.location.replace("#login");
},
resetPassword: function() {
window.location.replace("#reset");
},
render: function() {
this.$el.html(homeViewTemplate);
}
});
return HomeView;
});
I defined my app here
require.config({
//path mappings for module names not found directly under baseUrl
paths: {
jquery: 'vendor/jqm/jquery_1.7_min',
jqm: 'vendor/jqm/jquery.mobile-1.1.0',
underscore: 'vendor/underscore/underscore_amd',
backbone: 'vendor/backbone/backbone_amd',
text: 'vendor/require/text',
cordova: 'vendor/phoneGap/cordova',
wikitudePlugin: 'vendor/wikitude/WikitudePlugin',
plugin: 'plugin',
initOptions: 'initOptions',
main: 'main',
messages: 'messages',
templates: '../templates',
modules: '../modules',
model: '../model'
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'jquery': {
exports: '$'
},
'jqm': {
deps: ['jquery'],
exports: '$'
},
'initOptions': {
deps: ['jquery'],
exports: '$'
},
'main': {
deps: ['jquery'],
exports: '$'
},
'messages': {
deps: ['jquery'],
exports: '$'
},
'cordova': {
deps: ['jquery'],
exports: '$'
},
'wikitudePlugin': {
deps: ['jquery'],
exports: '$'
},
'underscore': {
exports: '_'
},
}
});
//1. load app.js,
//2. configure jquery mobile to prevent default JQM ajax navigation
//3. bootstrapping application
define(['app','jqm-config'], function(app) {
$(document).ready(function() {
console.log("DOM IS READY");// Handler for .ready() called.
});
app.initialize();
});
Why?
app isn't defined within your HomeView. It has no idea what it is (hence, 'cannot call method receivedEvent on undefined.
There are several ways to bind the context for a listener. You can have your bindEvents function do:
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
And change onDeviceReady to work with any instance of app, so just use this:
onDeviceReady: function() {
this.receivedEvent('deviceready');
},
define(['app','jqm-config'], function(app) {
document.addEventListener('deviceready', function (e) {
app.receivedEvent();
});
});
try this, then you don't have to set anything inside the initialize in your backbone.view and also can remove the bindEvent()

Optimize shim configuration

Is there any way to do something like following
shim: {
bsAlert || bsTooltip || dbDropdown: {
deps: ['jquery']
}
}
instead of following
shim: {
bsAlert: {
deps: ['jquery']
},
bsTooltip: {
deps: ['jquery']
},
bsDropdown: {
deps: ['jquery']
}
}
My shim list is getting too long; Is there any way, where i can use logical operator or regular expressions to optimize my shim configuration?
You probably already knew this but using || for this purpose won't work in plain JavaScript. I do not know of a JavaScript "extension" language (like CoffeeScript) which will allow what you propose.
However, the configuration object you pass to requirejs can be dynamically constructed. So you could do something like:
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... }
}
};
var s = config.shim;
s.bsAlert = s.bsTooltip = s.bsDropdown = { deps: ['jquery'] };
require.config(config);
If you are going to need to do this a lot, it would be possible to write a config like:
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... }
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
And then have a function walk over the config object to convert keys of the form "A || B" into what requirejs wants before passing the object to requirejs. And since requirejs combines configurations when you configure it multiple times, you could have something like:
require.config({
// ... minimal config allowing to find "convert_config"
});
var convert_config = require("convert_config"); // module returns function
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... },
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
convert_config(config); // modifies object in-place
require.config(config); // pass the full configuration to requirejs
Adding to #Louis-Dominique Dubeau answer. Definition for convert config can be given as follows.
define("convert_config", function(){
function convert_config(config){
for(var index in config.shim){
if(index.indexOf("||")!=-1){
var keys = index.split("||");
for(var i=0; i<keys.length; i++){
config.shim[keys[i]] = config.shim[index];
}
delete config.shim[index]
}
}
return config;
}
return convert_config;
})
var convert_config = require("convert_config");
var config = {
baseURL: "lib",
paths: {},
shim: {
moduleA: {},
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
config = convert_config(config);
require.config(config);

Configuring require.js for backbone-ui

I am trying to use the backbone-ui library but cannot figure out the require.js configuration to get the modules loaded.
main.js:
requirejs.config({
baseUrl: '/static/js/facebook_report_app/js',
paths: {
backbone: 'lib/backbone'
, underscore: 'lib/underscore'
, jquery: 'lib/jquery'
, laconic: 'lib/laconic'
, moment: 'lib/moment'
, backboneUI: 'lib/backbone-ui/js/backbone_ui'
, menuUI: 'lib/backbone-ui/js/menu'
, textUI: 'lib/backbone-ui/js/text_field'
, text: 'lib/text'
},
shim: {
'lib/underscore': {
exports: '_'
},
'laconic': {
deps: ["jquery"],
exports: "$.el"
},
'lib/backbone': {
deps: ['lib/underscore']
, exports: 'Backbone'
},
'backboneUI': {
deps: ['lib/backbone', 'laconic', 'jquery']
, exports: 'Backbone.UI'
},
'textUI': {
deps: ['jquery', 'lib/backbone', 'backboneUI', 'laconic']
, exports: 'Backbone.UI.TextField'
},
'menuUI': {
deps: ['lib/backbone', 'backboneUI', 'laconic', 'textUI']
, exports: 'Backbone.UI.Menu'
},
'lib/backgrid': {
deps: ['lib/underscore', 'lib/backbone']
, exports: 'Backgrid'
},
'report_app': {
deps: ['lib/underscore', 'lib/backbone', 'lib/backgrid', 'backboneUI']
}
}
});
require([
'facebook_report_app'
],
function(FacebookReportApp) {
window.fbReport = new FacebookReportApp();
});
menu_user.js
define(['jquery', 'lib/backbone', 'backboneUI', 'menuUI', 'laconic'], function(AccountPickerView) {
var AccountPickerView = Backbone.UI.Menu.extend({
el: '.left-nav',
});
return AccountPickerView;
});
When I load this in dev, the console reports "Object [object Object] has no method 'input' ", on line 44 of the text_field.js of the Backbone-UI library.
I suppose my configuration approach is broken to begin with -- I added the menu.js and text_field.js files bc I was getting errors 'Backbone.UI.Menu' and Backbone.UI.TextField' (a requirement of Menu) weren't defined. But there must be a cleaner way to bring in the various files of backbone-ui.
So how do I get rid of the 'no method input' error? Or better configure to use Backbone UI? Or should I be using jQuery UI in the first place? In which case, where do I go to figure out configuration of that?
I got it working, after much fiddling with the following setup:
js/main.js
requirejs.config({
baseURL: 'js',
urlArgs: "bust=" + (new Date()).getTime(),
shim: {
underscore: {
exports: '_'
},
jquery: {
exports: '$'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
laconic: {
exports: '$.el'
},
backbone_ui: {
deps: ['underscore', 'jquery', 'backbone', 'laconic', 'moment'],
exports: 'Backbone.UI'
}
},
paths: {
jquery: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min',
moment: './lib/moment.min',
laconic: './lib/laconic',
underscore: 'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
backbone: 'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min',
backbone_ui: './lib/backbone-ui',
crypto: 'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5',
templates: '../templates',
collections: './collections',
models: './models',
}
});
js/views/json.js
define(['jquery','underscore', 'backbone', 'backbone_ui'],
function($,_,Backbone, BBUI){
var JsonView = Backbone.View.extend({
className: "json-item",
initialize: function(data){
var self = this;
this.app = data.app;
this.model = data.model;
this.listenTo(this.model, "change", function(){
console.log("model changed", self.model);
});
this.model.fetch({
success: function(){
self.render();
}
});
},
render: function(){
var self = this;
$(this.el).empty();
for (key in this.model.attributes){
this.el.appendChild(new Backbone.UI.Label({content:key}).render().el);
this.el.appendChild(new Backbone.UI.TextField({model: this.model, content:key}).render().el);
}
this.el.appendChild(new Backbone.UI.Button({content:"save", onClick: function(){self.model.save()}}).render().el);
return this;
}
});
return JsonView;
});
Please note that I import backbone-ui as BBUI and never reference it that way. BBUI.TextField() is a defined function and using it would work as well, but the way Backbone-ui is set up it makes alterations to Backbone, Jquery, and Underscore when it loads. So I figured I just needed it to be run prior to the view getting loaded.

Categories