Access $ in a required file using Alloy - javascript

I am in my controller (ControllerA) and I have an external file that I want to handle orientation changes.
//-- In ControllerA
var gestures = require('gestures');
Inside gestures.js I need access to $ so I can manipulate some elements in ControllerA
Inside gestures.js I currently get undefined for $
I have successfully managed to get this to work by creating an init() function in gestures and I can intantiate the require like:
var gestures = require('gestures').init($); but this feels like a hack.
What is the proper way of doing this in alloy?
edit
Just a side note. I tried doing this with Ti.include() as well and same thing...no access to $

CommenJS modules (included in other controller using require ) must be independent off any other controllers. from it's name "gesture.js" i think you are trying to controle some orientations changes and shake gestures ... You have to define this module to use it in all other controllers and for that this feature exist.
for example suppose i have a module called animations.js :
var animations={};
animations.moveToLeft=function(element,newLeftValue){
var animation=Ti.UI.createAnimation({
left:newLeftValue,
duration:700
... so on
});
element.animate(animation);
};
module.exports=animations;
Then i can use this module from many other controller and to animate many titanium's objects
just require it in controller.js file and use moveToLeft function ...

Related

How can I access a service in config function or access a provider inside a service

I need to configure angular bootstrap tooltip (uibTooltip) to be disabled for mobile devices when using angular-bowser for device detection.
This could be done simply by:
isMobile = _bowser.mobile
$uibTooltipProvider.options = { trigger: isMobile ? "none" : "mouseenter" }
Problem: $uibTooltipProvider is a provider and bowser is a service.
I have to use $uibTooltipProvider in a config function while I can't use bowser service in a config function. And neither I can use $uibTooltipProvider in a run function where I can use bowser
I have already tried overriding the $get function as they suggest here but the "ontouchstart" event in $window does not apply for tablets where I want to keep tooltips enabled.
Is there any way I can get a workaround this?
I finally decided to inject a small css modification in run time. I had the three following options:
1. Use that hack on GitHub: I did not like the fact that in order to make it work I had to empirically (by placing a breaking point) find out which were the actual services injected in the $get function of the uibTooltipProvider. (see there is a difference between the services injected in the github thread and the ones I had to inject (see code snippet)
2. Add the bowser library and use it statically: I did not like this option because we are already using angular-bowser as a dependency for our DeviceDetector service, so we would be using the same library twice: one statically to configure the tooltip options and one in runtime for everything else.
3. Inject a small css modification (the option I chose):
public disableTooltipsForTouchScreen(): void {
if ( this._deviceDetector.isMobile() || this._deviceDetector.isTablet() ) {
let styleSheet = document.createElement("style");
styleSheet["innerHTML"] = ".tooltip { display: none; }";
document.body.appendChild(styleSheet);
}
}
And if we ever need to have a finest control over the bootstrap-tooltip configuration then I will consider option 2.

Cordova Plugins

Can someone explain me how does a structure of a javascript file written to execute a custom plugin work, for example I know that
exec(<success function>,<failure function>,<service>,<action>,<args>)
this function is used to call the native where service is the plugin class name and action is the method that needs to be called in that class.
What I am failing to understand is that what does this structure do for example
cordova.define("cordova/plugin/pluginName",
function(require,exports,module){
var exec = require("cordova/exec")
pluginName.prototype.methodName = function()
I am unable to understand what is happening here ?
You don't have to use cordova.define anymore, that's added automatically on plugin install
From the doc:
Do not wrap the file with cordova.define, as it is added
automatically. The module is wrapped in a closure, with module,
exports, and require in scope, as is normal for AMD modules.
var exec = require("cordova/exec") just loads the cordova.exec module into exec, if you don't do this you can call your plugin with cordova.exec(<success function>,<failure function>,<service>,<action>,<args>) instead of just doing exec(<success function>,<failure function>,<service>,<action>,<args>)
pluginName.prototype.methodName = function() just creates a methodName function for your pluginName, so it makes possible that the user can call your plugin method like pluginName.methodName()

Load requirejs module with data-bind (knockout.js)?

What I want to do is load js using the data-bind attribute. I am fairly new to requirejs and knockout and I'm not sure how to go out this.
Right now I have my js split into different require modules for each type of component I have. For example, I have a file that deals with the header dropdown (header.js):
define('headerDropdown',['jquery', 'bootstrap']),function(jquery, bootstrap){
var $menu = $(".menu");
var $dropdown = $menu.find("ul");
$menu.on("click", function () {
$dropdown.toggle("fast");
});
};
What I want to do is:
<div class="header" data-bind="headerDropdown">...</div>
And load the respective js.
Most of my js modules are UI changes based on clicks (show and hiding stuff on click) but I only want the js to load is the html block is on the page.
Hopefully this makes sense!
How can I do this using requirejs and knockout?
Looks like you are mixing concepts. First let's see the define() definition (suppose the file is headerDropdown.js):
define('headerDropdown',['jquery', 'bootstrap']),function(jquery, bootstrap){
var $menu = $(".menu");
var $dropdown = $menu.find("ul");
$menu.on("click", function () {
$dropdown.toggle("fast");
});
};
Require.js does not recommend to define a module expliciting their name ('headerDropdown'); you can get the name based on the filename. That's because require has a tool for optimization of the javascript in production: you can concatenate and minimize the output JS. The optimizer uses the filename to define the module name. Please, avoid defining with name.
If you look at the code, you are requiring ['jquery'] but inside the module definition you're using the global jQuery variable. That's OK because jQuery define their module as a global variable, but the convention is to receive in the function the jquery reference:
define('headerDropdown',['jquery', 'bootstrap']),function($, bootstrap)
You are defining a module that manipulates DOM directly, which goes against the DOM update procedure of knockout. In your case, you are using a data-bing="headerDropwodn" so the headerDropdown is a bindingHandler rather than a simple module. Please check: http://knockoutjs.com/documentation/custom-bindings.html
You can load on require as you pointed on the question. You just need to change your codes:
Load in your HTML an app.js script (for example). This app.js requires knockout and your headerDropdown bindingHandler. In the function declaration you define the ko.applyBindings and that's all.
Greetings!

How can I make requirejs polymorphically load a module?

I am currently developing a single page application using Cordova 3.4.0, Requirejs and Backbone. While porting my application from iPhone to iPad, I need to change some functions in some views and keep other parts intact.
To keep the change minimal, my solution is to create new object for each view I need to change, inherit all properties from original view and override only necessary functions.
To do so, I need to configure Requirejs so that in iPad, if I require, for instance, 'user/view/edit-profile.js', it will check whether there was a 'user/ipad/view/edit-profile.js' file, if there is one, requires it, otherwise require 'user/view/edit-profile.js'.
I have tried i18n, but it is not right for this situation. I am coming up with an idea of creating a new plugin for requirejs to do the task.
Does anyone have any suggestion for my problem?
Btw, Since the required file changes dynamically according to the platform. I call it polymorphism.
You could use path fallbacks:
paths: {
"user/view/edit-profile": ["user/ipad/view/edit-profile", "user/view/edit-profile"]
}
The above will make RequireJS try to load the ipad variant first. If as you develop your application you end up with logic to complex for fallbacks, you can use errbacks:
function onload(module) {
// Whatever you want to do...
};
require([module_a], onload, function (err) {
require([module_b], onload);
});
The code above will try to load a module from module_a and then from module_b. I use this kind of code to load modules with names that are computed at run time.
Since every module is a Backbone View, I come up with a solution, which will override extend function of Backbone View to return modified object depending on the existence of ipad, iphone or android dependencies.
The solution will require that if a base view have iPad version, it have to declare the iPad versions at dependencies, the extend function will extend existing view by the iPad view so that the iPad view can inherit all properties of base view and override only necessary functions.
I name the view PolyplatformView. Each view need to declare its ID, for example: user/view/edit-profile
Backbone.PolyplatformView = Backbone.View.extend({
});
Backbone.PolyplatformView.extend = function() {
if(arguments[0].moduleId) {
var extendPropsPath = arguments[0].moduleId.replace('/', '/' + constants.platform_name + '/');
// turn user/view/edit-profile -> user/ipad/view/edit-profile
if(require.defined(extendPropsPath)) {
_.extend(arguments[0], require(extendPropsPath));
}
} else {
console.warn('No module Id in polyplatform view -> cannot extend its parent');
}
var extended = Backbone.View.extend.apply(this, arguments);
return extended;
}

Appcelerator titanium - passing js variables

I am new to JS and Appcelerator titanium. I am trying to implement the MVC model to my app, but I have a problem accessing the data in the model:
in the model.js:
var my_val;
then in file1.js, I modified the value of my_val:
Ti.include("model.js");
my_val=5;
then in another file file2.js:
Ti.include("model.js");
T.API.info(my_val); // the value I always get is "undefined"
why is file2.js not detecting the change file1.js has done to my_val? Is there anyway to make it work?
take a look at my blog posting regarding this particular problem.
blog.clearlyinnovative.com
you want to include both files in your app.js and add the variable to your namespace; this is cleaner and doesn't pollute the global scope.
var myApp = {};
Ti.include("model.js");
Ti.include("file2.js");
in model.js do something like this
var myApp.model = {};
myApp.model.my_val = 100;
in file2.js do something like this; no need to incude model.js again, the value was set in your own namespace and is clearly defined
Ti.API.info(myApp.model.my_val);
If you want to get this functionality done use Titanium Properties so that you can get/set your variable as per requirement.Do something like this in your app.js
// initialize your variable, you can update it as well with your custom value
Titanium.App.Properties.setInt('my_value', 0);
You can get this value any where you want like this:
var myValue = Titanium.App.Properties.getInt('my_value');
This is because what the statement
Ti.include('model.js');
does is to just sort of 'copy-paste' the code in your 'model.js' file into the other two files. All the variables in 'model.js' will be available to the file in which you included 'model.js'. But this only means that a copy of the variable my_val is made available to 'file2.js' not a variable that is common to all files that have the Ti.include('model.js') line!Including a file in another is pretty much the same as typing out the lines of the first file into the second but it in no way connects all files that include a common file!
So maybe instead of
Ti.include('model.js');
Ti.API.info(my_val);
you can this try this seeing as you have already included 'model.js' in 'file1.js??'
Ti.include('file1.js');
Ti.API.info(my_val);
OR you can always go with Muhammad Zeeshan's advice and check out Ti.App.Properties. Good Luck! :)

Categories