How do I add a new JS function via mixin to the Magento checkout payment page's shipping information section? - magento2

I am trying to add a mixin in Magento 2 for the checkout/payment page shipping info section.
There is an existing section in vendor/magento/module-checkout/view/frontend/web/template/shipping-information/address-renderer/default.html as follows:
<each args="data: address().customAttributes, as: 'element'">
<text args="$parent.getCustomAttributeLabel(element)"/>
<br/>
</each>
I want to create a myNewFunction() and call it from here. So, I have temporarily added if="$parent.myNewFunction(element)" to it, like this:
<each args="data: address().customAttributes, as: 'element'">
<text if="$parent.myNewFunction(element)" args="$parent.getCustomAttributeLabel(element)"/>
<br/>
</each>
That pre-existing function getCustomAttributeLabel is defined in vendor/magento/module-checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js.
This is where I need to add my myNewFunction() at. I don't want to override that entire file and duplicate it into my theme, so I am trying to add the function to it via mixin.
To do this, I have stubbed out a module: app/code/MyCompany.
In this module, I have created:
app/code/MyCompany/Checkout/view/frontend/requirejs-config.js
with this code:
var config = {
config: {
mixins: {
'Magento_Checkout/js/view/shipping-information/address-renderer/default': {
'MyCompany_Checkout/js/view/shipping-information/address-renderer/default-mixin': true
}
}
}
};
Then I created the mixin itself in:
app/code/MyCompany/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default-mixin.js
with this code:
define([
'uiComponent',
'underscore',
'Magento_Customer/js/customer-data'
], function (Component, _, customerData) {
'use strict';
return function (target) {
return target.extend({
myNewFunction: function (element) {
console.log(element);
return false;
}
});
}
});
I currently have deploy mode set to "development" in Magento. Nonetheless, I have tried removing all the var/* files, generating static content again, and clearing the cache, for good measure.
No matter what, upon loading the checkout/payment page, I keep getting this JS error in the console:
$parent.myNewFunction is not a function
What am I doing wrong here?
I suspected the module needs to have a register.php? Or the module is not loading? Yet, I have seen plenty of other examples such as this guide, this Magento mixin stackoverflow question, and this example on how to add shipping.js functionality via mixin, none of which mention doing anything more with the module other than declaring the requirejs-config.js and the mixin JS file itself.

Just found a way to override that function using 'mixins'.
On requirejs-config.js file I had to add:
config: {
mixins: {
'Magento_Checkout/js/view/shipping': {
'Mynamespace_Mymodule/js/view/shipping': true
}
}
}

Related

this$store function is undefined

I am trying to use vuex's store to make some API calls but after installing vuex, importing store to my files and following other stack overflow answers, like making sure vuex is installed, if i am exporting my store file with " Vuex.Store" and etc but my loadCalls function is still not working.
This is the error i get:
this.$store.loadCalls is not a function
Here is my function and how i am trying to call it, it is declared in my ACTIONS section of my store.js file.
loadCalls() {
axios
.get("/some/calls")
.then(res => {
console.log(res)
});
},
I try using it in my beforeMount() when my component loads:
beforeMount(){
this.$store.loadCalls();
}
What am i doing wrong here?
If you defined an action like this:
actions: {
loadCalls() {
// ...
}
}
Then you would call it like this:
this.$store.dispatch('loadCalls');
Actions aren't exposed directly, you call them using dispatch.
https://vuex.vuejs.org/guide/actions.html#dispatching-actions

Get newly created id of a record before redirecting page

I would like to retrieve the id of a newly created record using javascript when I click on save button and just before redirecting page.
Do you have any idea please ?
Thank you !
One way to do this in Sugar 7 would be by overriding the CreateView.
Here an example of a CustomCreateView that outputs the new id in an alert-message after a new Account was successfully created, but before Sugar gets to react to the created record.
custom/modules/Accounts/clients/base/views/create/create.js:
({
extendsFrom: 'CreateView',
// This initialize function override does nothing except log to console,
// so that you can see that your custom view has been loaded.
// You can remove this function entirely. Sugar will default to CreateView's initialize then.
initialize: function(options) {
this._super('initialize', [options]);
console.log('Custom create view initialized.');
},
// saveModel is the function used to save the new record, let's override it.
// Parameters 'success' and 'error' are functions/callbacks.
// (based on clients/base/views/create/create.js)
saveModel: function(success, error) {
// Let's inject our own code into the success callback.
var custom_success = function() {
// Execute our custom code and forward all callback arguments, in case you want to use them.
this.customCodeOnCreate(arguments)
// Execute the original callback (which will show the message and redirect etc.)
success(arguments);
};
// Make sure that the "this" variable will be set to _this_ view when our custom function is called via callback.
custom_success = _.bind(custom_success , this);
// Let's call the original saveModel with our custom callback.
this._super('saveModel', [custom_success, error]);
},
// our custom code
customCodeOnCreate: function() {
console.log('customCodeOnCreate() called with these arguments:', arguments);
// Retrieve the id of the model.
var new_id = this.model.get('id');
// do something with id
if (!_.isEmpty(new_id)) {
alert('new id: ' + new_id);
}
}
})
I tested this with the Accounts module of Sugar 7.7.2.1, but it should be possible to implement this for all other sidecar modules within Sugar.
However, this will not work for modules in backward-compatibility mode (those with #bwc in their URL).
Note: If the module in question already has its own Base<ModuleName>CreateView, you probably should extend from <ModuleName>CreateView (no Base) instead of from the default CreateView.
Be aware that this code has a small chance of breaking during Sugar upgrades, e.g. if the default CreateView code receives changes in the saveModel function definition.
Also, if you want to do some further reading on extending views, there is an SugarCRM dev blog post about this topic: https://developer.sugarcrm.com/2014/05/28/extending-view-javascript-in-sugarcrm-7/
I resolved this by using logic hook (after save), for your information, I am using Sugar 6.5 no matter the version of suitecrm.
Thank you !

Ext.define() order

I'm using Extjs5 and Sencha Cmd, and I'm working on a l10n engine (over gettext) to implement localization.
Suppose I want to offer a translation function to every class of my project, named _().
In every controller, view, model and any class, I'd like to be able to write something like that:
Ext.define('FooClass', {
someStrings: [
_('One string to translate'),
_('A second string to translate'),
_('Yet another string to translate')
]
});
First problem: _() must exist before all the Ext.define() of my project are executed. How to achieve that?
Second problem: _() is looking in "catalogs" that are some JavaScript files generated from .po files (gettext). So, those catalogs must have been loaded, before all the Ext.define() of my app are executed.
_() is a synchronous function, it musts immediately return the translated string.
Edit concerning the edited question
You have at least two ways to load External libraries:
Ext.Loader.loadScript
loadScript( options )
Loads the specified script URL and calls the supplied callbacks. If
this method is called before Ext.isReady, the script's load will delay
the transition to ready. This can be used to load arbitrary scripts
that may contain further Ext.require calls.
Parameters
options : Object/String/String[] //The options object or simply the URL(s) to load.
// options params:
url : String //The URL from which to load the script.
onLoad : Function (optional) //The callback to call on successful load.
onError : Function (optional) //The callback to call on failure to load.
scope : Object (optional) //The scope (this) for the supplied callbacks.
If you still run into problems you can force the loader to do a sync loading:
syncLoadScripts: function(options) {
var Loader = Ext.Loader,
syncwas = Loader.syncModeEnabled;
Loader.syncModeEnabled = true;
Loader.loadScripts(options);
Loader.syncModeEnabled = syncwas;
}
Place this in a file right after the ExtJS library and before the generated app.js.
Old Answer
You need to require a class when it is needed, that should solve your problems. If you don't require sencha command/the ExtJS class system cannot know that you need a specific class.
Ext.define('Class1', {
requires: ['Class2'],
items: [
{
xtype: 'combo',
fieldLabel: Class2.method('This is a field label')
}
]
});
For further reading take a look at:
requires
requires : String[]
List of classes that have to be loaded before instantiating this
class. For example:
Ext.define('Mother', {
requires: ['Child'],
giveBirth: function() {
// we can be sure that child class is available.
return new Child();
}
});
uses
uses : String[]
List of optional classes to load together with this class. These
aren't neccessarily loaded before this class is created, but are
guaranteed to be available before Ext.onReady listeners are invoked.
For example:
Ext.define('Mother', {
uses: ['Child'],
giveBirth: function() {
// This code might, or might not work:
// return new Child();
// Instead use Ext.create() to load the class at the spot if not loaded already:
return Ext.create('Child');
}
});
Define the translate function outside the scope of the ExtJs project and include it before the Ext application is included in the index.html.
The scripts are loaded in the right order and the _() function is ready to use in your whole project.
i18n.js
function _() {
// do the translation
}
index.html
<html>
<head>
<script src="i18n.js"></script>
<script id="microloader" type="text/javascript" src="bootstrap.js"></script>
</head>
<body>
</body>
</html>

Can I divide my tests into separate specs and then call them from another or is it better to use helper functions?

Just got started with Protractor for E2E testing and I am having a bit of trouble with the test case structure.
Not sure if can I divide my tests into separate specs and then call them from another or how can I make nice helper functions to handle this.
I am finding elements by a repeater and then I would like to make tests for each of the operation for each of the element in the repeater. Sort of like this:
describe('tasty', function () {
'use strict';
var ptor;
beforeEach(function () {
ptor = protractor.getInstance();
ptor.get('http://localhost:8000/');
});
it('Should sample three tasty fruits of every kind on my shopping list.', function () {
ptor.findElement(protractor.By.className('fruitstore')).click();
var fruitshelves = ptor.findElements(protractor.By.repeater('fruit in fruits').column('header'));
fruitshelves.then(function(arr) {
for (var i=0;i<arr.length; i++) {
// Pick up three fruits of this kind from the shelf and put in shopping cart
// Should be listed on my shopping list
// Open the wallet
// Should have money
// Pay for the fruits and put it in your shopping bag
// Should be able to complete the transaction
// For each one of the fruits in your shopping bag
// Take a bite
// Should be tasty
}
});
});
});
Based on the #langliman answer, I've managed to achieve the desired behaviour.
Note login.spec.js and Login.page.js should be located in the same folder.
Login.page.js file:
var LoginPage = function (ptor) {
//following PageObject pattern define the functions here.
}
module.exports.getLoginPage = function (ptor) {
return new LoginPage(ptor);
};
login.spec.js file:
(function () {
'use strict';
describe('login page', function () {
var ptor = protractor.getInstance();
var loginPageBuilder = require('./Login.page.js');
var loginPage = loginPageBuilder.getLoginPage(ptor);
it('should login as admin', function () {
loginPage.visit();
loginPage.enterUsername('user');
loginPage.enterPassword('password');
loginPage.login();
});
});
}());
I came to this question looking for a way to have helper functions shared between spec files in Protractor. In case others are looking for the same, turns out since Protractor is just running in Node, all you need to do is var helpers = require('./your-helper-file').
In case you want shared setup and before/after functions as well as helper methods, one solution is to require the tests from your spec helper instead of requiring your spec helper from the tests.
conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['e2e/spec.js']
}
e2e/spec.js
var chai = require('chai'),
homepage = require('./homepage.js'),
signin = require('./signin.js');
chai.should()
browser.baseUrl = 'http://localhost:3000'
homepage.test()
signin.test()
e2e/homepage.js
exports.test = function() {
describe('homepage', function() {
it('should have the right title', function() {
browser.get('/')
browser.getTitle().then(function(title){
title.should.eq('Home')
})
});
});
}
e2e/signin.js
exports.test = function() {
describe('signin', function() {
it('should have the right title', function() {
browser.get('/signin')
browser.getTitle().then(function(title){
title.should.eq('Sign in')
})
});
});
}
I'm looking at the same thing myself, and to some extent I had hoped that you would have an answer for me on this question. :-)
Having said that, it appears that protractor is new enough that nobody really knows the answer, and I guess that makes my answer as good as the next persons.
Firstly, I'm using the page object notation that is described on the protractor getting started page, towards the bottom: https://github.com/angular/protractor/blob/master/docs/getting-started.md
This gives an element of modularity, my view here is that I end up with a set of classes, one per page, that abstract away some of the detail. So, for example, I might have a "foo" class, which includes in it abstractions like "foo.get" and "foo.validate(id, name, otherData)". This would be a way to pull out repeated code.
The bit that I haven't worked out is how to create a library of modules and then assemble those into a single set of scenarios. I have a few thoughts though:
The underlying problem is the ability to include javascript files in each other - which really doesn't exist as a capability. There are third party libraries, which I'd prefer not to use, and I haven't seen a way to use Angular's module capability to do this.
End 2 end testing can be very dependent on the order of the tests. So one test may create data, another test may then use that data. As an example, if you want a test that logs people on, you may need a test that registers people first. You probably don't want to put registration on the front of every test that you run. As such, you probably need a lot of control over the order of your test scenarios anyway
As such, one option is to just put everything in one really big file. Which goes against everything we all learned in school, but I haven't really come up with a reason that wouldn't work. Then you can write functions and abstractions to your hearts content.
If you follow that to the next stage, another option is to write a series of javascript files with strict naming conventions, then use grunt to concatenate them for you before executing them. So, for example:
A set of files named xxxx.page.scenario.js, which contain the "page object" definitions - basically helper methods for each page
A set of files named xxxx.functions.scenario.js, which contain common components of your scenarios - so maybe you have a register and logon set of actions, and you make that into a library function
A set of files named nnxx.scenarios.scenario.js, which contain the actual scripts themselves. These are numbered at the start (the nn), so we can concatenate them in a reliable sequence and thereby control which order our scripts run
I'm not yet saying this is a good idea, just that it at least superficially looks like it could work, and would give the desired result. My main concern is that it feels fragile - so as the test suite grows in size it would perhaps become very difficult to maintain. Perhaps another way to do this would be, instead of numbering the scenarios, to instead define them as dependencies, and have something that makes sure that any given script runs after any script it declares itself to be dependent on. That would maybe allow for subsetting of the scripts as well - so you could say "run the bar script" and the framework would know that the bar script needs the foo script run first, and maybe the login script. But it's OK to leave all the other scripts out.
EDIT: I see astrolabe as potentially a good answer here, it looks like it explicitly allows you to modularise your tests. https://github.com/stuplum/astrolabe. I've just completed a proof of concept with it, and it seems to do everything I might hope. The code for it ends up something like:
clubs.part.scenario.js:
/**
* Partial for the page objects associated with clubs
*/
var Page = require('astrolabe').Page;
module.exports = Page.create({
url: { value: 'UI/index.html#clubs' },
title: { get: function() { return this.findElement(this.by.id('title')); } },
description: { get: function() { return this.findElement(this.by.id('description')); } },
clubTableElement: { value: function(rowNum, columnBinding) {
return this.findElement(this.by.repeater('club in clubs').row(rowNum).column(columnBinding)); } }
}
);
clubs.scenario.js:
/**
* End to end tests for the club functionality
*/
var homePage = require('../home/home.part.scenario.js');
var clubsPage = require('./clubs.part.scenario.js');
describe( 'Navigate to club list page', function() {
it ( 'should allow navigation to the club list page', function() {
homePage.go();
expect(homePage.clubsLink.getText()).toEqual('Clubs');
homePage.clubsLink.click();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
it ( 'should allow us to go directly to the club list page', function() {
clubsPage.go();
expect(clubsPage.title.getText()).toEqual('Club functions');
expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server');
expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');
expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');
expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');
expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');
});
});
I'm pretty happy with this structure, it doesn't do everything but it does most things. The sample code I've provided is from the tutorial that I've been working on for a while with angularjs, which I'm updating for e2e testing and Rails 4 at the moment, if you want the context that goes with that: http://technpol.wordpress.com/2013/11/16/5-end-to-end-testing/

Wordpress: Accessing A Plugin's Function From A Theme

I'm trying to add some functionality from a plugin I have made into a Wordpress theme but I am having little joy. The documentation doesn't really help me solve the problem so perhaps someone here can help.
I have a plugin in Wordpress that is activated and working fine. The class for this plugin has a function called generateHtml which I would like to access from a Wordpress Theme. But whatever I try, I cannot seem to access my plugin's code.
Can either give me a summary of what I need to do to get a theme accessing code from a plugin and/or point out there I am going wrong in my code:
Plugin:
<?php
/** Usual comments here **/
if (!class_exists("ImageRotator")) {
class ImageRotator {
private $uploadPath = '';
private $pluginPath = '';
private $options;
function __construct() {
$this->uploadPath = dirname(__file__).'\\uploads\\';
// add_shortcode('imagerotator', array(&$this, 'generateHtml'));
}
// Various functions for plugin
function generateHtml() {
echo '<p>Hello World</p>';
}
}
}
/**
* Create instance of image rotator
*/
$imageRotator = new ImageRotator();
/**
* Create actions & filters for Wordpress
*/
if (isset($imageRotator)) {
// Actions
add_action('admin_menu', array(&$imageRotator, 'createMenu'));
add_action('admin_init', array(&$imageRotator, 'registerSettings'));
add_action('imagerotator_show', array(&$imageRotator, 'generateHtml'));
}
Portion from theme header page:
<?php if (isset($imageRotator)) {
$imageRotator->generateHtml();
} else if (isset($ImageRotator)) {
print_r($ImageRotator);
} else {
echo '<p>Nope!</p>';
}
if (function_exists("imagerotator_show")) {
echo 'Function found';
} else {
echo 'Function NOT found';
}
?>
Currently all I ever see is "Nope" and "Function NOT found". Thanks for any input.
Lee,
For starters, "imagerotator_show" is not a function; it's the name of a type of action. When you use the add_action() function, Wordpress just adds your method to the list of functions/methods to call when a particular action is triggered. Thus your second test will always respond with 'Function NOT found'.
The most likely cause of the first problem is failing to declare the method you want to call as a public method. You're also making the code harder than it needs to be.
The best practice I've seen for declaring methods and registering hooks from a class looks something like this:
if ( ! class_exists( 'Foo' ) ):
class Foo {
function __construct() {
add_action( 'hook_name', array( &$this, 'my_hook_implementation' ) );
}
function my_hook_implementation() {
// does something
}
public function my_special_method() {
// does something else
}
}
if ( class_exists( 'Foo' ) ):
$MyFoo = new Foo();
This allows your class to keep all of its implementation details private. When you need to call my_special_method(), you do it as follows:
$MyFoo->my_special_method();
#andrew since I can't comment I thought I would answer your ancillary question. See:
http://net.tutsplus.com/tutorials/wordpress/create-wordpress-plugins-with-oop-techniques/
Where it is explained that when defining a callback function from an object you have to use the array function. It's basically saying get the function 'my_hook_implementation' from the object $this and use it as the callback parameter to the add action hook. It is because you defined the function within the scope of the object and you have to define the scope in order for PHP to know what function you are talking about. The scope being the object referred to by the variable $this.
You just need to use do_action() function, inside your theme.
If you want the function generateHtml to appears inside your header.php you just need to open the header.php file and paste <?php do_action('imagerotator_show'); ?> where you want and then your function will be called there.