PureScript's purescript-jquery package supports this
before :: JQuery -> JQuery -> Effect Unit
method, which "Inserts an element before another" as shown in its documentation on pursuit.
Is there a similar function somewhere, which inserts an element after another?
I do not see such a method documented on Pursuit. If it does not exist, then how might I implement the same effect?
I have very little experience with PureScript and its FFI, but just looking at the implementation of before:
foreign import before :: JQuery -> JQuery -> Effect Unit
I'm going to take a wild stab at this being what you want:
foreign import after :: JQuery -> JQuery -> Effect Unit
and then in a corresponding js file for your module:
exports.after = function(ob) {
return function(ob1) {
return function() {
ob1.after(ob);
};
};
};
Related
I'm doing Angular JS tutorials. I've no clue why this notation have been used. Can anyone explain what is happening here?
Code in the controller.js file:
var vm = this;
vm.openSideBar = openSideBar; // Did not understand this line
function openSideBar() {
$mdSidenav('left').open();
};
The code that you post is purely stylistic and takes advantage of hoisting to enable the bindable functions to be displayed at the top of the file, and the details (implementations) for those to be kept separate and specified further down the file.
Benefits
The benefits of this approach are more apparent as the number of bindable functions in the controller increases:
Easier to read (what's important). Since the purpose of the controller is to support the view and supply it with bindings, the what is more important than the how i.e. What the view can bind to is more important than how the controller goes about it's work. You can see immediately on opening the file what the controller can do for the view.
Easier to find (the details). Having the bindable functions at the top of the file acts as like a contents page for the file. Most IDE's will highlight matching variables if you place the cursor over them and that helps find the implementation details further down the file.
Encourages single responsibility. Your controller should be supplying bindings for a view, and only one view. You can see at the top of your file if you start to build up lots of unrelated bindable functions that serve different purposes that you might be trying to do too much in one controller.
Encourages named functions. This is particularly useful for debugging as it means that you will have less anonymous functions in your application, which in turn makes reading call stacks in developer tools easier.
Further Reading
Check out John Papa's Angular 1 Style Guide which has been approved by the Angular team. You can read all about the thought behind this approach under the heading Bindable Members Up Top in the Controllers section (although it can be applied to factories/services/directives also).
openSideBar was add to view model. it was aviable to run this func from view like <someElement ng-click="$ctrl.openSideBar()"></someElement>
The VM model or way of doing is quite old... before ES6 came along.
Nowadays, I would suggest you learn ES6, take a look at Todd Motto's AngularJS style guide https://github.com/toddmotto/angularjs-styleguide.
But here an answer to your question:
// OLD WAY
function MyAppController() {
var vm = this;
vm.colors = ['red', 'blue', 'green'];
vm.getBlue() {
return vm.colors[1];
}
vm.handleClickEvent(e) {
// this keyword is now the dom element, not your controller
// this is why the VM pattern came to life.
this.classList.add(vm.getBlue());
}
}
// NEW WAY
class MyAppController {
$onInit() {
this.colors = ['red', 'blue', 'green'];
}
getBlue() {
return this.colors[1];
}
handleClickEvent(e) {
// Here this keyword is still your controller, NOT the dom
// element (provided you used angular's ng-click directive
const elem = e.target;
elem.classList.add(this.getBlue);
}
}
With ES6, it is rare that you have to same a reference to this since you can use arrow functions. You should also get familiar with bind(), call(), and apply() methods to control which context you want to apply to functions.
I'm fairly new to protractor and promises in general. I've had a look around, and although there's many posts out there about returning promises, or the results from queued actions none of them make much sense to me, so i'm after a fairly easily described answer to what I hope is a simple question!
I am trying to write some protractor tests for my angularjs website.
I am using bootstrap and angular mainly, no other third party libraries, other than the occasional angular add-on such as toaster, and bootstrap modal.
I have several 'arrangement steps' before I get to the assertion part of my test. Let's say :
a) Person logs in
b) Person accesses options form ( which may or may
not be displayed already on the screen depending on some external
factors, but if it's not present they can open it with a button press
).
c) Person performs an action on the options form.
d) assert that the text box on the form now contains the correct value.
I can get my test to pass quite easily when the form is already on the screen, but the bit that's getting me stuck is step b) where I need to check first if the form is active and click a button if it's not pefore proceeding to step c.
I've tried to return the promise from isDisplayed like so :
//
// Is the user settings form active at the mo?
//
function _isUserSettingsFormActive()
{
var result = element(by.id(logoutFormID)).isDisplayed;
return result;
}
But if I call .then on _isUserSettingsFormActive() I get the following error :
[31mTypeError: undefined is not a function[0m
However if I output the results of _isUserSettinsFormActive() I see the below, so I know it's returning something :
function () {
return self.elementArrayFinder_[fnName].
apply(self.elementArrayFinder_, arguments).toElementFinder_();
}
All I want to do is check if an item exists and act on that before performing my assert.
It needs to be in a function, as this code will be used in many places throughout my test suit. It's not the 'expect' itself, more a step that may or may not need an action to set up the browser for my test to pass.
isDisplayed is a function, so it should be called like that:
function _isUserSettingsFormActive()
{
var result = element(by.id(logoutFormID)).isDisplayed();
return result;
}
Protractor does not work like the Java or C# bindings of Selenium would (it's funner but more work to achieve what would be simple actions in Java or C#). It would be safer to return a count promise if the options form is also not in the DOM but if it is in the DOM and just hidden you could use isDisplayed(). I wrote two examples below for both situation including clicking the button depending on the condition.
Option 1 (Not present in DOM and not displayed):
function _isUserSettingsFormActive() {
//$$('#logoutFormId') is the equivalent of element.all(by.id('logoutFormId'))
$$('#logoutFormId').count().then(function(num){
if(num < 1) {
element(by.id('openLogoutButton').click();
}
});
};
OR
Option 2 (Present in DOM but not displayed):
function _isUserSettingsFormActive() {
//$('#logoutFormId') is the equivalent of element(by.id('logoutFormId'))
$('#logoutFormId').isDisplayed().then(function(visible){
if(!visible) {
element(by.id('openLogoutButton').click();
}
});
};
I am trying to have external modules change my $translateProvider.translation on the main module. see this as a "tranlation plugin" for my app.
it seems like changing translations from the $translate service is not possible.
mymodule.service('MyService', function ($translateProvider) {
var lib = function () {
//EDITED FOR BREVITY
this._registerTranslations = function (ctrl) {
if (!ctrl.i18n) return;
for (var name in ctrl.i18n) {
/////////////////////////////
// THIS IS THE PLACE, OBVIOUSLY PROVIDER IS NOT AVAILABLE!!!!
$translateProvider.translations(name, ctrl.i18n[name]);
//////////////////////////////
}
};
//EDITED FOR BREVITY
};
return new lib();
});
anyone with a bright idea?
So, to answer your question: there's no way to extend existing translations during runtime with $translate service without using asynchronous loading. I wonder why you want to do that anyway, because adding translations in such a way means that they are already there (otherwise you would obviously use asynchronous loading).
Have a look at the Asynchronous loading page. You can create a factory that will load a translation from wherever you want.
I created an Angular constant to hold new translations. If I want to add a new translation, I add it to the constant. Then in my custom loader, I first check the constant to see if the translation exists (either a new one, or an updated one). If so, I load it from the constant. If not, I load it from a .json file (or wherever you load your initial translations from). Use $translate.refresh() to force translations to be reloaded and reevaluated.
Demo here
The demo is pretty simple. You would need to do a little more work if you wanted to just change a subset of the translations, but you get the general idea.
From the AngularJS docs (https://docs.angularjs.org/guide/providers):
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Providers are to be used with the application's .config function. $translateProvider for configuration, $translate for other services and controllers.
Many of the views in my application need to be "collapsible". To the user this means that you can click an arrow to collapse or expand the view's contents.
When creating a view I need to be able to easily say, "This view should be collapsible," and then run the appropriate setup code (which essentially means adding the .collapsible class to the view's wrapper and inserting a dom element that looks like this: <div class="toggle"></div>
Suggestions on ways to pull this off seamlessly? I'm currently using Backbone, Backbone.Marionette, and Underscore.
I do this with another application that doesn't use Backbone. In that application every action results in a page refresh, so I just use jQuery to look for all elements with the .collapsible class and do my setup that way.
EDIT:
I'm using Backbone.Marionette.CompositeView for these particular views, if that helps.
I've done similar thing in my project by extracting such functionality into mixins. There're different approaches to implementing mixins in Backbone. Take a look here or here
You can create parent view that extends from Marionettes compositeView and add your common functionallity there, and have your project views extend from this parent view.
var CollapsibleView = Backbone.Marionette.CompositeView.extends({
variable1: 1,
var2: true,
initialize : function() {
// your code here
},
helperfunction : function () {
// other helpful function
}
});
var MySpecificView = CollapsibleView.extends({
mySpecificFunction : function () {
// some specificView functionality
}
});
var myProjectView= new MySpecifcView();
myProjectView.helperfunction(); /// function from the parent
myProjectView.mySpecificFunction(); /// function from the specificView
/// you also have the functionality added on the initialization of the collpasibleView
I'm attempting to learn backbone.js and (by extension) underscore.js, and I'm having some difficulty understanding some of the conventions. While writing a simpel search filter, I thought that something like below would work:
var search_string = new RegExp(query, "i");
var results = _.filter(this, function(data){
return search_string.test(data.get("title"));
}));
But, in fact, for this to work I need to change my filter function to the following:
var search_string = new RegExp(query, "i");
var results = _(this.filter(function(data){
return search_string.test(data.get("title"));
}));
Basically, I want to understand why the second example works, while the first doesn't. Based on the documentation (http://documentcloud.github.com/underscore/#filter) I thought that the former would have worked. Or maybe this just reflects some old jQuery habits of mine... Can anyone explain this for me?
I'd guess that you're using a browser with a native Array#filter implementation. Try these in your console and see what happens:
[].filter.call({ a: 'b' }, function(x) { console.log(x) });
[].filter.call([1, 2], function(x) { console.log(x) });
The first one won't do anything, the second will produce 1 and 2 as output (http://jsfiddle.net/ambiguous/tkRQ3/). The problem isn't that data is empty, the problem is that the native Array#filter doesn't know what to do when applied to non-Array object.
All of Underscore's methods (including filter) use the native implementations if available:
Delegates to the native filter method, if it exists.
So the Array-ish Underscore methods generally won't work as _.m(collection, ...) unless you're using a browser that doesn't provide native implementations.
A Backbone collection is a wrapper for an array of models, the models array is in c.models so you'd want to:
_.filter(this.models, function(data) { ... });
Backbone collections have several Underscore methods mixed in:
Backbone proxies to Underscore.js to provide 28 iteration functions on Backbone.Collection.
and one of those is filter. These proxies apply the Underscore method to the collection's model array so c.filter(...) is the same as _.filter(c.models, ...).
This mixing-in is probably what's confusing the "should I use the native method" checks that Underscore is doing:
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
You can use _.filter on a plain old object (_.filter({a:'b'}, ...)) and get sensible results but it fails when you _.filter(backbone_collection, ...) because collections already have Underscore methods.
Here's a simple demo to hopefully clarify things: http://jsfiddle.net/ambiguous/FHd3Y/1/
For the same reason that $('#element') works and $#element doesn't. _ is the global variable for the underscore object just like $ is the global variable for the jQuery object.
_() says look in the _ object. _filter says look for a method named _filter.