Angular Mixins integration - mixins

I'm trying to offer a SORT functionality amongst all my modules and I'd like to know integrate this. Does Angular support some sort of mixin?
I'd like the mixin to inject new properties (models) and methods to the controller associated to the module. These properties and methods should only use their associated controller's scope.
I know I could use underscore _.extend or jQuery.extend() , but I'd like to know if there's a cleaner way to do this in a true Angular spirit.
Regards.

One year later:
You can use scope inheritance! You can have a main controller with all the functionality you want to share and then you can specify child controllers in the following way:
HTML:
<body ng-controller="MainCtrl">
<div id="wrapper" ng-controller="SectionCtrl">
...
</div>
</body>
MainCtrl:
function MainCtrl($scope) {
$scope.sorter = { array: [], sort: function() { } };
}
SectionCtrl:
function SectionCtrl($scope) {
$scope.sorter.array = [1,2,3];
$scope.sorter.sort();
}
No need to declare $scope.sorter since MainCtrl has already declared it. Scope inheritance in angular works pretty much like scope inheritance in Javascript.

Yes! and it is very simple.
I can give you an example how to achieve that:
(...)
.controller('ParentCTRL', ['$scope', function($scope) {
$scope.base_func= function() {
//Do something
};
}]);
.controller('ChildrenCTRL', ['$controller', '$scope', function($controller, $scope) {
$controller('ParentCTRL', {$scope: $scope});
// Now you can access base_fun() from here
}]);
.controller('SecondChildrenCTRL', ['$controller', '$scope', function($controller, $scope) {
$controller('ParentCTRL', {$scope: $scope});
// Now you can access base_fun() from here
}]);

I'm not sure exactly what you're trying to do, but it sounds like you want a Service, which is then dependency-injected into your controllers and directives.

Related

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

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
}
}
}

Dynamic Vue Form from Input-Elements

I'm building a reusable vue-form-component. For more flexibility the basic idea is to NOT have to specify the form information in the vue-data-object beforehand, but to get the data-structure from the dom-input-elements itself.
On instance-creation the "v-model" attributes are read from the input-tags and applied to the instance via vue.set()
This works fairly well: https://jsfiddle.net/seltsam23/hrL3ec3z/9/
One detail is missing though: I need to only query the children-input-fields, and not the site-wide fields in case I'm using more than one form-component at the same time:
created() {
var inputs = document.querySelectorAll('input'); // works, but this returns ALL elements
var inputs = this.$el.querySelectorAll('input'); // Doesn't work because $el is only available after mounted().
...
}
mounted() {
var inputs = this.$el.querySelectorAll('input'); // works, but attribute "v-model" is removed from inputs at this point
...
}
I've tried to create data-path attribute in the created() phase to store the v-model value on the element itself, but after mount all those created attributes disappear.
Any ideas how to achieve this in an elegant way?
You should be aware that the only reason you see v-model attributes at all is that you're using inline-template. They are in the DOM during the created phase because the template has not yet been processed. What I'm saying is that you're trying to do something pretty hacky, and you probably shouldn't.
It's backward to the normal Vue approach of having the data model drive the DOM, but I know that in some cases it is useful to initialize things from the HTML.
How about this approach?
Vue.component('my-form', {
props: ['init'],
data() {
return {
form: {}
}
},
created() {
this.form = this.init;
}
})
new Vue({
el: '#vue',
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="vue">
<my-form inline-template :init="{foo: {bar: 'one', baz: 'two'}}">
<form>
<input type="text" v-model="form.foo.bar">
<span v-text="form.foo.bar"></span>
<hr>
<input type="text" v-model="form.foo.baz">
<span v-text="form.foo.baz"></span>
</form>
</my-form>
</div>

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>

jqGrid adding a class to column by function

There's similar question here, but using cellatrr for whole column is quite overloaded. I know there's classes attribute, but it can be only set by static text. I would like to use a function instead like:
$("#jqgrid").jqGrid({
...
colModel:
[
{
name:'a',
index:'a',
classes: function() {
return (a < b ? "ui-state-error" : "ui-state-highlight");
}
]
});
Any ideas? Of course without modding jqGrid core :)
'title'=>'Name',
'name'=>'name',
'classes'=>'your class'
may be you can useful. check below link
http://guriddo.net/documentation/php/_2v70w5p2k.htm

How to call custom filters in Zend?

I want to use htmlpurifier on my website, but can't figure out how to load my filter in the view. I've added my filter the way described in the first answer here.
I want to be able to call it from my view with something like $this->filter($content) Any suggestions how I do that?
It is a two step process:
Write an actual Zend_Filter implementation of HTMLPurifier (done, answer in the question you mentioned)
Write a view helper
It will look like this:
class My_View_Helper_Purify extends Zend_View_Helper_Abstract
{
public function purify($value)
{
$filter = new My_Filter_HtmlPurifier();
return $filter->filter($value);
}
}
Don't forget to add your custom view helper path:
$view->addHelperPath(
APPLICATION_PATH . '/../library/My/View/Helper',
'My_View_Helper_'
);
And later in any of your view scripts:
<?= $this->purify($text) ?>