Knockout - foreach databind in 2 column table layout - html

I have the following table where I'm attempting to loop through coverage lines. I would like 2 columns with a different line in each, however my code duplicates the same coverage in each column. Any suggesions on how to get a 2 column layout without the repetition? Which element should my foreach binding go on? Thanks.
<table class="coverage-table" data-bind="foreach: $root.clientVM.CustomCoverageLines">
<tr>
<td>
<input type="checkbox" data-bind="checked: Checked" />
<label>
<span data-bind="text: $data.Description"></span>
</label>
</td>
<td>
<input type="checkbox" data-bind="checked: Checked" />
<label>
<span data-bind="text: $data.Description"></span>
</label>
</td>
</tr>
</table>

You could add a computed property to your model that structures the data in the way that you want. See this JSFiddle for an example: http://jsfiddle.net/6gvtz51g/. An advantage to this approach is that you can specify a different row size if you would like.
HTML
<table data-bind="foreach: coverageLineRows">
<tr data-bind="foreach: $data">
<td>
<span data-bind="text: $data"></span>
</td>
</tr>
</table>
JavaScript
function ViewModel () {
var self = this;
self.coverageLines = ko.observableArray([
'Medical',
'Dental',
'Vision',
'Life'
]);
self.coverageLineRowSize = ko.observable(2);
self.coverageLineRows = ko.computed(function () {
var rows = [];
var i = 0;
var lines = self.coverageLines();
var size = self.coverageLineRowSize();
while (i < lines.length) {
rows.push(lines.slice(i, i += size));
}
return rows;
});
}
ko.applyBindings(new ViewModel());

How do you feel about this as a solution? Its not as flexible as the solution given by #JackieChiles in that it would need some tweaking to work with different amounts of rows. But the code I've provided does provide for a prettier look for two columns and it also has the ability to keep track of the check boxes next to each of your items. I suspect a combination of both our solutions will be in your end product :)
var vm = function () {
var self = this;
this.array = ko.observableArray([{
name: ko.observable('Medical'),
checked: ko.observable()
}, {
name: ko.observable('Dental'),
checked: ko.observable()
}, {
name: ko.observable('Vision'),
checked: ko.observable()
}, {
name: ko.observable('Life'),
checked: ko.observable()
}, {
name: ko.observable('Other'),
checked: ko.observable()
}]);
this.coverageSplit = ko.computed(function () {
var retArray = [];
var i = 0;
var arrayUnWrapped = this.array();
while (i < arrayUnWrapped.length) {
if (i >= arrayUnWrapped.length - 1) {
retArray.push({
col1: arrayUnWrapped[i],
col2: {
name: '',
checked: false,
hideThisCheck: true
}
})
console.log(retArray[retArray.length - 1]);
break;
}
retArray.push({
col1: arrayUnWrapped[i],
col2: arrayUnWrapped[i + 1]
});
i += 2;
}
return retArray;
});
this.check_click = ko.observable('None');
this.setLastClicked = function (name) {
if (name.length > 0) self.check_click(name);
};
};
ko.applyBindings(vm);
Here is a fiddle of it in action http://jsfiddle.net/ozrevulsion/sva9tnje/

Related

Nesting options under an if binding causes wrong behavior

I want to have a <select> without using the options binding, and nest the <option> element under an if binding.
The following is what I did (here's also a fiddle), which displays a behavior I wasn't expecting: The if seems to fire for each option selection, whereas what I expected is that it would fire only when adding the options elements to DOM.
Thus, when an option is chosen, it doesn't displayed. Only when choosing the same option again, it renders as it should.
What did I do wrong?
var DogHouseViewModel = function() {
var self = this;
self.allowedNames = ["A", "B", "C"];
self.puppies = ko.observableArray([]);
self.createPuppy = function () {
self.puppies.push(new DogViewModel());
}
self.isNameAlreadyTaken = function (puppyName) {
var puppies = self.puppies();
for (var i = 0; i < puppies.length; i++) {
if (puppies[i].dogName() == puppyName) {
return true;
}
}
return false;
}
self.printPuppiesName = function () {
self.puppies().forEach(function (puppy) {
alert(puppy.dogName())
})
}
}
var DogViewModel = function (dogName) {
var self = this;
self.dogName = ko.observable();
}
vm = new DogHouseViewModel()
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
<div>
<button data-bind="text: 'create a puppy', click: createPuppy"></button>
<button data-bind="text: 'print puppies names', click: printPuppiesName"></button>
<div data-bind="foreach: puppies">
<select data-bind="value: dogName">
<!-- ko foreach: $parent.allowedNames -->
<!-- ko if: !($root.isNameAlreadyTaken($data)) -->
<option data-bind="value: $data, text: $data"></option>
<!-- /ko -->
<!-- /ko -->
</select>
</div>
</div>
I believe this is what you are trying to do. The problem is that your allowedNames are the values of the options do you can't just remove them from the array. But you can clone the parent array and as it changes compute the array by returning a list of not used values.
I also added a check to make sure we don't accidentally add a puppy object to the puppies array when no names are available.
var DogHouseViewModel = function() {
var self = this;
self.allowedNames = ["A", "B", "C"];
self.puppies = ko.observableArray([]);
self.createPuppy = function() {
var newPuppy = new DogViewModel(self);
if(newPuppy.allowedNames().length > 0) { // Check to see if there are any names left.
self.puppies.push(newPuppy);
}
}
self.removePuppy = function(obj) {
self.puppies.remove(obj);
}
self.printPuppiesName = function() {
self.puppies().forEach(function(puppy) {
alert(puppy.dogName())
})
}
}
var DogViewModel = function(parent) {
var self = this;
self.dogName = ko.observable();
self.allowedNames = ko.computed(function() {
var allowedNamesClone = parent.allowedNames.slice(0);
var usedNames = parent.puppies().filter(function(pup) { // get all pups who have a name
return pup.dogName() !== '' && pup.dogName() !== self.dogName();
})
usedNames.forEach(function(pup) {
var index = allowedNamesClone.indexOf(pup.dogName());
if (index > -1) {
allowedNamesClone.splice(index, 1); // remove name from cloned array
}
})
return allowedNamesClone; // return new array
})
}
vm = new DogHouseViewModel()
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
<button data-bind="text: 'create a puppy', click: createPuppy"></button>
<button data-bind="text: 'print puppies names', click: printPuppiesName"></button>
<div data-bind="foreach: puppies">
<!-- ko if: allowedNames().length > 0 -->
<select data-bind="options: allowedNames, value: dogName"></select>
<button data-bind="click: $root.removePuppy">x</button>
<!-- /ko -->
</div>
</div>

Knockout observable field in array to indicate order of items

I have a html view that's connected to Knockout viewmodel, and displays a list of items.
Each item in the list contains a textual name field, and a numeric order field.
A user can perform a "drag and drop" action to items in the UL list.
The "drag and drop" event changes the order of the items as follows:
<div id="wrapper">
<ul data-bind="foreach:Items">
<li draggable="true"
ondragover="event.preventDefault();"
data-bind="event:{dragstart:$root.dragItem,drop:$root.dropItem}">
<label data-bind="text:name"></label>
<label data-bind="text:orderNo"></label>
<input type="text" data-bind="value:name" />
</li>
</ul>
<script type="text/javascript">
var list = [{ name: 'Red', orderNo: 0 }
, { name: 'Green', orderNo: 1 }
, { name: 'Blue', orderNo: 2 }];
function viewmodel() {
var self = this;
self.Items = ko.mapping.fromJS(list);
self.ItemToDrag = ko.observable();
self.dragItem = function (item, event) {
self.ItemToDrag(item);
return true;
}
self.dropItem = function (item, event) {
event.preventDefault();
var up = self.ItemToDrag().orderNo() > item.orderNo();
self.ItemToDrag().orderNo(up ? item.orderNo() - 0.5 : item.orderNo() + 0.5);
//order this list
self.Items.sort(function (left, right) {
return left.orderNo() == right.orderNo() ? 0 : (left.orderNo() < right.orderNo() ? -1 : 1);
});
//set integer number
for (var i = 0; i < self.Items().length; i++) {
self.Items()[i].orderNo(i);
}
}
}
var vm;
$(document).ready(function () {
vm = new viewmodel();
ko.applyBindings(vm, $("#wrapper")[0]);
});
My question is, if it is possible with Knockout to change the contents of the order field automatically when the items of the list change their order through the UI.
Something like
<ul data-bind="foreach:Items,orderKey:orderNo"></ul>
Where orderKey indicates the order of the items, and which field to update in case of order change.
I'm not sure this is exactly what you need. This is custom binding, that sorts an array from foreach binding before:
ko.bindingHandlers.foreach["after"] = ["orderKey"];
ko.bindingHandlers.orderKey = {
update: function (el, valueAccessor, allBindingsAccessor, viewModel) {
var key = ko.unwrap(valueAccessor());
var allBindings = allBindingsAccessor();
if("foreach" in allBindings) {
var array = ko.unwrap(allBindings.foreach);
array.sort(function(a, b) { return a[key] > b[key]; });
allBindings.foreach = array;
}
}
};
// The model
var model = { Items: ko.observableArray([{text: 3}, {text: 1}, {text: 2}]) };
// Apply
ko.applyBindings(model);
// This simulate changes in observableArray
setTimeout(function() { model.Items.push({text: 0}) }, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<ul data-bind="foreach: Items, orderKey: 'text'">
<li data-bind="text: text"></li>
</ul>
No, there is no specific binding for that use case. In knockout, however, it is simple to write a custom binding. See the documentation. In the company I'm working for, we're using a knockout-based framework (developed by us) with tons of custom bindings, some of them really complex.
I just started to create such a binding for your use case. But I realized, it won't fit the purpose unless you have dozens of such lists.
What you can do, however, is to sort put the actual sorting into a knockout computed and just do the updating of the sort index in your drop function. See example below and don't hesitate to ask if something is not clear.
var list = [{ name: 'Red', orderNo: 0 }
, { name: 'Green', orderNo: 1 }
, { name: 'Blue', orderNo: 2 }];
function viewmodel() {
var self = this;
self._items = ko.mapping.fromJS(list);
self.Items = ko.pureComputed(function () {
return self._items().sort(function (a, b) {
return a.orderNo() < b.orderNo() ? -1 : 1;
});
});
self.ItemToDrag = ko.observable();
self.dragItem = function (item, event) {
self.ItemToDrag(item);
return true;
}
self.dropItem = function (item, event) {
event.preventDefault();
var up = self.ItemToDrag().orderNo() > item.orderNo();
self.ItemToDrag().orderNo(up ? item.orderNo() - 0.5 : item.orderNo() + 0.5);
}
}
var vm;
$(document).ready(function () {
vm = new viewmodel();
ko.applyBindings(vm, $("#wrapper")[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<div id="wrapper">
<ul data-bind="foreach:Items">
<li draggable="true"
ondragover="event.preventDefault();"
data-bind="event:{dragstart:$root.dragItem,drop:$root.dropItem}">
<label data-bind="text:name"></label>
<label data-bind="text:orderNo"></label>
<input type="text" data-bind="value:name" />
</li>
</ul>

AngularJS delete default empty option in directive

I have this directive that brings sub-categories by the categoryId in this application the categories are called services and the sub-categories are called services-child( just for you to know ).
ok
The File that contain the directive service-detail.php has:
<services-child serviceid="{{id}}"></services-child>
The directive :
'use strict';
app.directive('servicesChild', function ($window,$state,servChildService) {
return {
require: '^form',
restrict: 'EA',
scope: {
serviceid: '#',
},
templateUrl:'assets/views/partials/service-child.php',
link: function ($scope, $element, $attributes) {
var serviceId = $attributes.serviceid;
$scope.childs = servChildService;
servChildService.loadServiceChilds(serviceId);
$scope.serviceChilds = servChildService.serviceCH;
}
};
});
app.factory('serviceChildResource', ['$resource', function($resource) {
return $resource("/services/serviceChild/:id", {id: '#id'}, {
getChilds: {
method: 'GET'
}
});
}]);
app.service('servChildService', function(serviceChildResource) {
var self = {
'isLoading': false,
'showBlock': true,
'serviceCH': [],
'loadServiceChilds': function(serviceId){
if (!self.isLoading) {
self.isLoading = true;
var params = {
'id': serviceId,
};
self.serviceCH = [];
serviceChildResource.getChilds(params, function(data){
if(data.childs.length > 0){
angular.forEach(data.childs, function(value, key){
self.serviceCH.push(new serviceChildResource(value));
self.isLoading = false;
self.showBlock = true;
});
}else{
self.showBlock = false;
self.isLoading = false; //show the loading.
}
});
}
}
};
return self;
});
Now the services-child view is this service-child.php:
<div class="panel panel-white" ng-show="childs.showBlock">
<div class="panel-heading border-light">
<h4 class="panel-title"><span class="text-bold">Add More Services</span>
</h4>
</div>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="sample-table-1">
<thead>
<tr>
<th>Service</th>
<th>Description</th>
<th>Price</th>
<th>Qty.</th>
<th>Select</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="service in serviceChilds">
<td>{{service.name}}</td>
<td ng-bind-html="service.description">
{{service.description}}
</td>
<td>${{service.price}}</td>
<td>
<qty-select ng-hide="{{service.single_service}}"
price="{{service.price}}"
id="{{service.id}}"
indexid = {{$index}}>
</qty-select>
</td>
<td><input type="checkbox" value="{{service.id}}"
ng-model="$root.servCheck[service.id]"
name="servCheckN"/></td>
</tr>
</tbody>
</table>
<div ng-show="childs.isLoading">
<span us-spinner="{radius:10, width:5, length:4, lines:8}"></span>
</div>
</div>
</div>
Ok Now in this directive I have another Directive that has the Dynamic DropDown:
as you see this is the directive:
<qty-select ng-hide="{{service.single_service}}"
price="{{service.price}}"
id="{{service.id}}"
indexid = {{$index}}>
</qty-select>
Now this directive code is this qty-select.js:
'use strict';
app.directive('qtySelect', function ($window,$state,servChildService,$localStorage,$rootScope,$timeout) {
return {
require: '^form',
restrict: 'EA',
scope: {
indexid: '#',
},
templateUrl:'assets/views/partials/qty-select.php',
link: function ($scope, $element, $attributes) {
var i = 1;
while (i < 16) {
$scope.selectObj.push({'value' : $attributes.price * i,
'label' : i + ' (' + $attributes.price * i + ')',
'price' : $attributes.price * i,
'qty' : i,
});
i += 1;
};
console.log($rootScope.priceQty);
}
};
});
So basically what this directive does is creating a select option element
but it shows the price multiply by the index Ex. 1($10) which increment one by one
Ex. 2($20) so the result is something like this: if you pass 10 to the directive in the price attribute it will show:
<select ng-init="$parent.priceQty[indexid] = selectObj[0]"
ng-model="$parent.priceQty[indexid]" ng-change="updatePrice()"
ng-options="option.label for option in selectObj"
class="ng-valid ng-not-empty ng-dirty ng-valid-parse ng-touched" style="">
<option value="?"></option>
<option label="1 (15)" value="object:77">1 (15)</option>
<option label="2 (30)" value="object:78">2 (30)</option>
<option label="3 (45)" value="object:79">3 (45)</option>
<option label="4 (60)" value="object:80">4 (60)</option>
<option label="5 (75)" value="object:81">5 (75)</option>
<option label="6 (90)" value="object:82">6 (90)</option>
<option label="7 (105)" value="object:83">7 (105)</option>
<option label="8 (120)" value="object:84">8 (120)</option>
<option label="9 (135)" value="object:85">9 (135)</option>
</select>
Now this all works fine but I don't know how to get ride of the first empty option that angular append to the dropDown.
This is the View directive for select qty-select.php
<select ng-init="$root.priceQty[indexid] = selectObj[0]"
ng-model="$root.priceQty[indexid]" ng-change="updatePrice()"
ng-options="option.label for option in selectObj" >
</select>
<!-- <select ng-model="$root.priceQty[indexid]" ng-change="updatePrice(indexid)">
<option ng-repeat="value in selectObj" value="{{value.value}}"
ng-selected="$index == 1">{{value.label}}</option>
</select> -->
As you see in the I am trying with ng-repeat and with ng-options but
i am having problems with both.
Now if I work with $scope it works but when I am trying to use root
it does not work.
I notice that in my view select i have set
<select ng-init="$root.priceQty[indexid] = selectObj[0]"
but in the html that gets populated I see
<select ng-init="$parent.priceQty[indexid] = selectObj[0]"
$parent why ? is changing it.
and I need to set these input in the rootScope because I have to submit the form and I can no access to those values if I don't set the ng-model to be sent to the rootScope.
Also I tried to do this in the qty-select.js directive
after I build the select element i added this:
$scope.priceQty = $scope.selectObj[0];
and it worked but when I use $rooScope it doesn't work it says undefined.
$rootScope.priceQty = $scope.selectObj[0];
Any Idea?
Thank you
Hi thank you very much for your feedback...
Im not using $rootScope and a fixed the problem with the empty.
I had a lot architectural mistakes and thank you for your recommendations.
I totally change the way of using the directive.
Ok the way I solved the empty option was
'use strict';
app.directive('qtySelect', function ($window,$state,servChildService,$timeout,cartService,$cookies,$rootScope) {
return {
require: '^form',
restrict: 'EA',
scope: {
indexid: '#',
serviId: '#id',
servobj: '=',
},
templateUrl:'assets/views/partials/qty-select.php',
link: function ($scope, $element, $attributes) {
var i = 1;
var index = 0;
$scope.selectObj = [];
$scope.cartArray = [];
while (i < 16) {
$scope.selectObj.push({'value' : $attributes.price * i, //the value of the option tag (obligatory)
'label' : i + ' (' + $attributes.price * i + ')', //the copy (obligatory)
'price' : $attributes.price * i,
'qty' : i,
'serviceId' : $attributes.id,
'index' : index,
});
i += 1;
index += 1;
};
$timeout(function() {
document.getElementById("qty-"+$scope.indexid)[1].selected = true
//add the attribute ng-checked to filter them later.
document.getElementById("qty-"+$scope.indexid)[1].setAttribute("selected", 'selected');
}, 10);
}
};
});
I'm targeting the element by id and I am adding timeout because
the first load return undefined it seems the DOM is not ready
at that point so adding a timeout it give it enough time to the DOM to be ready.
Also I am adding the attribute selected="selected" manually since the selected true does not add the attribute selected and I need it to select later the whole element.
$timeout(function() {
document.getElementById("qty-"+$scope.indexid)[1].selected = true
//addinf manyally the attribute selected
document.getElementById("qty-"+$scope.indexid)[1].setAttribute("selected", 'selected');
}, 10);
Thank you
If you have recommendations are welcome.
This is the html directive:
<select ng-model="priceQty" ng-change="updatePrice(indexid,serviId,this)"
name="priceQty" id="qty-{{indexid}}">
<option ng-repeat="(key, value) in selectObj" value="{{value.price}}"
qty="{{$index+1}}" service-id="{{serviId}}">
{{$index+1}} ({{value.price}})
</option>
</select>

Angularjs does not update the data retrieved from the $http service

I'm trying to retrieve some data from a service using Angularjs. Initially, I want to just show the first 10 elements. Then, when the user clicks on a button (with ng-click="next()"), I want the same function to be triggered again in order to get the next 10 elements.
Here's my controller:
Admin.controller('orders', function ($scope, $http) {
var startIndex = 0;
const count = 10;
function retrieveData(startIndex, count) {
$http({
method: 'POST',
url: '/Admin/order/GetOrders',
data: { "startIndex": startIndex, "count": count }
})
.success(function (data) {
$scope.orders = data;
startIndex = startIndex + count;
$scope.$apply();
});
};
retrieveData(startIndex, count);
$scope.next = retrieveData(startIndex, count);
};
Now, what happens is that the function retrieveData() works perfectly the first time, but when I click the button nothing happens. I know for sure that the "click" event triggers the function, because I tried to replace the code with an alert, but I don't understand why the function retrieveData() itself only works the first time.
What am I missing?
<div class="container admin" ng-controller="orders">
<table class="table">
<tbody>
<tr ng-repeat="order in orders| filter:{OrderStatus: 'Hto'} | filter:query | filter:'!'+showCancelled | orderBy:predicate:reverse">
<td>
{{order.UserName}}
</td>
<td>
<span ng-class="{ 'label label-danger' : isLate }">
{{order.OrderDate}}
</span>
</td>
<td>
{{order.Country}}
</td>
<td>
<span ng-class="{ 'label label-warning' : order.OrderStatus == 'HtoPreAuth' || order.OrderStatus == 'SalePreAuth'}">
{{order.OrderStatus}}
</span>
</td>
</tr>
</tbody>
</table>
<a href="" ng-click="retrieveData()">
next
</a>
</div>
You are supposed to make the changes inside the $apply method:
Admin.controller('orders', function ($scope, $http) {
var startIndex = 0;
const count = 10;
$scope.retrieveData() { // No parameters
$http({
method: 'POST',
url: '/Admin/order/GetOrders',
data: { "startIndex": startIndex, "count": count }
})
.success(function (data) {
startIndex = startIndex + count;
$scope.orders = data;
if(!$scope.$$phase) {
$scope.$digest();
}
});
}
$scope.retrieveData();
};
// And the view
<a ng-click="retrieveData()"></a>
Edit:
Remove the parameters from the $scope.retrieveData function since they will be undefined
if you call the function with ng-click="retrieveData()"

Define multiple html amd modules in one file

Is there any way to do a requirejs define in a text document? Or an html document?
I have a document filled with header and cell templates for a grid
<body>
<th data-fieldname="PatientPerson">Name <span data-bind="attr: { class: sortField() == 'PatientPerson' ? 'inline-block' : 'hide' }"></span></th>
<td><span class="glyphicon glyphicon-expand"></span><a data-bind="click: function () { $parent.loadReportSummary(PatientPerson.ID()) }"><span data-bind="text: PatientPerson.FullName"></span></a></td>
<th data-fieldname="StudyType">Study Type <span data-bind="attr: { class: sortField() == 'StudyType' ? 'inline-block' : 'hide' }"></span></th>
<td data-bind="text: StudyType"></td>
<th data-fieldname="ServiceDate">Service Date<span data-bind="attr: { class: sortField() == 'ServiceDate' ? 'inline-block' : 'hide' }"></span></th>
<td data-bind="text: ServiceDate"></td>
<th>Export Summary</th>
<td><a data-bind="click: function (data) { $parent.exportReportSummary(data, PatientPerson.ID, SummaryID, !StudyExported()) }">View</a></td>
<th>Print All Reports</th>
<td><a data-bind="click: function (data) { $parent.printAllReports('/PrintReports/Reports?summaryID=' + SummaryID) }">Print</a></td>
etc.......
</body>
In another module I have an array which determines which of these columns are used in a knockout computed observable. I was hoping that I could make each of these a module instead of parsing them using jquery, but I wanted them to all be in one file. I'm using the text plugin for requirejs, but there seems to be no way to declare each of these as a module inside of one file, and it seems wasteful to have to split each of these into separate files.
maybe something like
<!--export name:"PatientPerson" -->
<th data-fieldname="PatientPerson">Name <span data-bind="attr: { class: sortField() == 'PatientPerson' ? 'inline-block' : 'hide' }"></span></th>
<td><span class="glyphicon glyphicon-expand"></span><a data-bind="click: function () { $parent.loadReportSummary(PatientPerson.ID()) }"><span data-bind="text: PatientPerson.FullName"></span></a></td>
<!-- /export-->
Then referencing the module like
require('filename').PatientPerson;
I created a plugin where you can add a !define to the end of the require on some file, and it will make the spec suggested from the OP work. It works with the official text plugin for requirejs.
define(['text', 'module'], function (text, module) {
var exportRegExp = /<!--\s*?export[^>]*>([\s\S]*?)<!--\s*?\/export\s*?-->/g,
masterConfig = (module.config && module.config()) || {},
buildMap={};
text.export = function (content) {
var exports = null;
if (content) {
var matches = content.match(exportRegExp) || [],
match, _i, _len;
exports = matches.length ? {} : null;
for (_i = 0, _len = matches.length; _i < _len; _i++) {
match = matches[_i];
var exportName = match.match(/(<!--\s*?export\s*?name\:")(.*?)\"\s*?-->/).slice(-1)[0];
exports[exportName] = match.replace(/<!--\s*?export[^>]*>\n?/, '').replace(/<!--\s*?\/export\s*?-->/, '');
}
}
return exports;
};
var baseParseName = text.parseName;
text.parseName = function(name) {
var index, parseExport = false;
index = name.indexOf('!export');
if (index !== -1) {
parseExport = true;
name.split('!export').join('');
}
var out = baseParseName(name);
out["strip"] = { "export": parseExport, "strip": out["strip"] };
return out;
};
text.finishLoad = function (name, strip, content, onLoad) {
var exports = strip.export ? text.export(content,name) : content;
if (exports == null) content = strip.strip ? text.strip(content) : content;
else content = exports;
if (masterConfig.isBuild) {
buildMap[name] = content;
}
onLoad(content);
};
text.write = function (pluginName, moduleName, write, config) {
if (buildMap.hasOwnProperty(moduleName)) {
var content = text.jsEscape(buildMap[moduleName]);
write.asModule(pluginName + "!" + moduleName,
"define(function () { return '" +
content +
"';});\n");
}
};
});
The following will work
require([text!somefile!define],function(){})
This also works but it ignores the !strip command if any exports exist in the file.
require([text!somefile!strip!define],function(){})
then you can call
require(['someModuleNameInDefineComment'],function(){})
I have not handled strip with a beginning define in the header.
Here is a Gist