mardi 27 septembre 2022

Listening to a service property change in an EmberJs Octane Component

I am wondering how on Emberjs Octane to fire a function in a component after a service property changes. Here is an example of how I did it before octane.

child-component.js before Octane

import Component from '@ember/component';
import {inject as service} from '@ember/service';
import {computed, observer} from '@ember/object';
import { isEmpty } from '@ember/utils';
import { on } from '@ember/object/evented';
export default Component.extend({

userAccount: service(),
childNavigation: service(),

whenUserChanges: on('init', observer( 'userAccount.user', 'childNavigation.{activeIgdiMeasure,currentChild}', function () {

        this.getChildItems();
    }))
})

Observers aren't recommended and @tracked isn't working on a service so I am not sure how to convert the whenUserChanges function to Octane.




jeudi 22 septembre 2022

Ember 4.6 Deployment problem -- router not routing

I'm doing my first deployment of an Ember app. I've managed to get the compiled app to load the main page with my navbar, but none of the links (which use the LinkTo builtin component) work.

I thought this might be an Apache problem so I wrote an .htaccess file to redirect all requests to the index.html file. With that, when I directly enter, for example:

http://localhost/myApp/user (user is a route)

I get the user index page. But none of the links on that page work either.

Ember Inspector shows that all of the routes appear to be available but I can't seem to access them using LinkTo.

Thanks for any help!




mardi 20 septembre 2022

Modifying Ember.js Components from Console

My company does A/B testing for clients who have sites built with various CRM/Middleware providers. One them uses a product built on the Ember.js framework. I do not have access to the source code for the site itself. I need to change the value of a selector component upon page load which I am planning on doing with a Javascript one-liner.

Unfortunately, I can't just change the value of the DOM element directly using document.getElementByID('selectorElement) as this won't trigger other events on the page. I tried using document.getElementByID('selectorElement).click() which had no effect on the page at all. I think it has to be done by interfacing with Ember directly, but I'm not very familiar with the framework.

As an example, imagine you were to navigate to https://guides.emberjs.com/release/. An answer to this question would be a script that can be run in the console that would change the version selector from the default to one of the other options.

The HTML for the component in question is below.

<select name="_name_" data-test-selector="_name_" data-test-form-field-input="_name_" aria-invalid="false" id="ember53-input" class="_inlineSelectInput_tuesss _selectInputBase_tuesss _inputBase_tuesss _inlineInputBase_tuesss _inlineSelectInput_tuesss _selectInputBase_tuesss _inputBase_tuesss _inlineInputBase_tuesss ember-view">
          <option disabled="" hidden="" value="">
              Select a type
          </option>
          <option value="Option1">
            Option1
          </option>
          <option value="Option2">
            Option2
          </option>
          <option value="Option3">
            Option3
          </option>
      
</select>



General questions on: Ember DDAU, Glimmer components (this.args), JavaScript getters and encapsulation

I work on an Ember team using ES5, Octane and Glimmer and am generally happy with the tech stack. I've written JavaScript webapps for about 12 years, doing fullstack work before that. I'm reviewing a bunch of code that somehow got merged into our solution (partially my fault because I didn't review the related PRs before they were merged) and am trying to settle an argument with the dev who wrote it.

This dev - who as an experienced dev should know better - built a whole section of our app that repeatedly does the following:

  1. Ember route gets this.model from the API and passes it as @model to a controller
  2. Ember controller passes @model to a child component as @model
  3. Ember component uses a JavaScript getter to create a "mask" or alias for part of the model: get localObject() { return this.args.model.parentObject; } and passes that getter (as this.localObject) to another child component. This getter is really just an alias because it does not apply any logic, it just makes typing the code faster for the dev.
  4. The second (or third or forth) child component receives the "masked" model as this.args.maskedModel, then uses another getter to mask that: get localModel() { return this.args.maskedModel; }, then the "final" child component directly mutates the passed-in property by calling set on it: set(this.localModel, 'someSubProperty', true);

Right now, the dev who used this antipattern ALL OVER the work they wrote is arguing that since this "works" that it's fine and it doesn't need to be refactored. I'm arguing this pattern breaks encapsulation, DDAU, misuses JavaScript getters and somehow forces two-way data binding across them and Glimmer's this.args object.

Personally, I don't even understand how this is working, since JavaScript getters and Glimmer's this.args object are both supposed to only allow one-way data binding. But somehow, when the child component mutates the passed-in objects from the parent (reaching across TWO different getters), the parent magically gets the updated object. Instead of directly mutating the passed-in objects, the child component should call a passed-in closure action from the parent and allow the parent to mutate the data.

I also think it is a misuse of JavaScript getters to use them as an alias to make referring to this.args.model.someObject easier (less typing), without applying any logic in the getter function. Ember has a computed property "alias" for this purpose, though I still think "aliasing" this.args.something in a component is a bad idea because it gives a dev the false notion they can directly mutate the alias, if they don't realize it is referring to a passed-in value from the parent.

I think all this bad code directly breaks Data Down, Actions Up in Ember, as well as the long-standing computer science principle of data encapsulation.

Does anyone know why this is working since ES5 getters and Glimmer's this.args object are supposed to be one-way and immutable? Is it a flaw in Ember/Glimmer? We are on Ember 3.28 now, is this fixed in a newer version? How can I explain to this developer, who is being stubborn on this, that this is a terrible way to write code??




lundi 19 septembre 2022

Sub set of list using Java Script

I am trying to create a sub set of the list from a given list.

For example, I have a list of fields which can be checked and unchecked. I am trying to create a sub list which will only have those items which are checked.

I am unable to create it using Javascript as I am very new to the language. Can someone please help me with it?

this.attributeCategoryOptions.forEach((el) => {
  el.description += ' Required';
});

if (this.args.formData.descriptionDefaultFieldId)
  this.descriptionDefaultFieldSelected = this.descriptionDefaultFieldOptions.find((el) =>
    this.args.formData.descriptionDefaultFieldId === el.id);

if (this.args.formData.iconUrl)
  this.iconUrlSelected = this.iconUrlOptions.find((el) =>
    this.args.formData.iconUrl === el.id);

if (this.args.formData.attributeDescriptionIdOptions != null) {
  this.attributeCategoryOptions.forEach((listItem) => {
    listItem.checked = false;
    this.args.formData.attributeDescriptionIdOptions.forEach((attr) => {
      if (listItem.id === attr.id) {
        listItem.checked = attr.checked;
      }
    });
  })



vendredi 16 septembre 2022

Difference between and in Ember JS

When I use did-update without wrapping using <div>, the action using in did-update fall into infinite loop. After wrapping with <div>, the problem has solved.

Here's an example code: (current is service which shows the current status)

Does not work: (when this.current.locationId changed, this.updateStates be executed infinitly)


Does work:

<div >
</div>

JS file:

@tracked property;

@action
updateStates() {
  //do something with `this.current.locationId`
  //change value of `property`
  //so template re-render cause of `property` changed
  ...
}

I guess the problem happens because of the tracking frame. But I can not exactly see why that kind of problem is happening.




jeudi 15 septembre 2022

Ember 4.6

Am I missing something in the following:

<select
  id=
  name=
  
>
  <option value="null">Select one ... </option>
  

  
  
  
    <option
      value=
      selected=
    ></option>
  
</select>

The selected option is not being identified when the is first loaded. The statements show that one of the records have @curVal and item.id having equal values. Using the and

typeof  get(item.id)

and the same for @curVal shows they are both strings.

I originally used ember-truth-helpers, with


but that never selects anything. So I wrote a local function:

@action
  areEqual(curval, itemId) {
    console.log('typeof curval', typeof curval);
    console.log('typeof itemId', typeof curval);
    return curval == itemId;
} 

but it never seems to be called. What am I doing wrong?




Brocolli Plugin ENOENT no such file auto-import-fastboot.js error

I randomly get the following error message when running the tests on an ember project, it doesn't happen all the time.

  - broccoliBuilderErrorStack: Error: ENOENT: no such file or directory, open '/tmp/broccoli-16293IqYV1TN4ouUv/out-402-bundler/lazy/auto-import-fastboot.js'
    at Object.openSync (fs.js:462:3)
    at Object.writeFileSync (fs.js:1384:35)
    at Bundler.addLazyAssets (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/bundler.js:119:20)
    at Bundler.<anonymous> (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/bundler.js:81:22)
    at Generator.next (<anonymous>)
    at fulfilled (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/bundler.js:11:58)
  - code: [undefined]
  - codeFrame: ENOENT: no such file or directory, open '/tmp/broccoli-16293IqYV1TN4ouUv/out-402-bundler/lazy/auto-import-fastboot.js'
  - errorMessage: ENOENT: no such file or directory, open '/tmp/broccoli-16293IqYV1TN4ouUv/out-402-bundler/lazy/auto-import-fastboot.js'
        at Bundler
-~- created here: -~-
    at new Plugin (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/broccoli-plugin/index.js:7:31)
    at new Bundler (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/bundler.js:32:9)
    at AutoImport.makeBundler (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/auto-import.js:62:16)
    at AutoImport.addTo (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/auto-import.js:72:38)
    at EmberApp.host.addonPostprocessTree (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-auto-import/js/auto-import.js:106:29)
    at EmberApp.toTree (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-cli/lib/broccoli/ember-app.js:1825:17)
    at module.exports (/home/jenkins/agent/workspace/project/embercli/projectName/ember-cli-build.js:113:20)
    at Builder.readBuildFile (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-cli/lib/models/builder.js:52:14)
    at Builder.setupBroccoliBuilder (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-cli/lib/models/builder.js:66:22)
    at new Builder (/home/jenkins/agent/workspace/project/embercli/projectName/node_modules/ember-cli/lib/models/builder.js:32:10)
-~- (end) -~-
  - errorType: Build Error
  - location:
    - column: [undefined]
    - file: [undefined]
    - line: [undefined]
    - treeDir: [undefined]
  - message: ENOENT: no such file or directory, open '/tmp/broccoli-16293IqYV1TN4ouUv/out-402-bundler/lazy/auto-import-fastboot.js'

VERSIONS:

  • ember-cli: 3.14.0
  • broccoli-asset-rev: 3.0.0
  • brotli: 1.0.9
  • node: 12.22.12



mercredi 14 septembre 2022

How to track getter change in other getter without computed - Ember js

I need to track the getter is loaded or not in other getter without @computed property. How can I do?

@computed('current.locationId')
get currentApplications() {
  const query = {
    locationID:     get(this, 'current.locationId')
  };
  
  return this.store.pagedArray(this.store.query('shift-application', query));
}

get applicationsLoaded() {
  return this.currentApplications.isFulfilled
}

I need to track currentApplications.isFulfilled without using @computed('currentApplications.isFulfilled').




fall into infinite loop in ember js

I need to get store data when some properties change. Property value exist in the service, so I re-execute function using . But this action fall into infinite loop when the service property value changes.

This is my code.

  • js file
export default class CurrentApplications extends Component {

  @service store;
  @service current;
  @service permissions;

  @tracked currentApplications = emberA([]);

  constructor() {
    super(...arguments);
    next(()=> {
      this.currentApplications.pushObject(this.loadCurrentApplications.perform());
    });
  }

  @task
  *loadCurrentApplications() {
    const query = {
      page:     this.currentApplications.length + 1,
      per_page: 10,
      from:     moment().subtract(1, 'minutes').format(),
      until:    moment().add(1, 'minutes').format(),
      state:    ["accept", "assigned", "cancelled", "superseded"]
    };

    const locationId = this.current.locationId;
    if (locationId) query.location_id = locationId;

    if (get(this, 'current.user.isStaff')) {
      set(query, 'user_ids', get(this, 'current.user.id'))
    }

    return yield this.store.query('shift-application', query);
  }

  @lastValue('loadCurrentApplications') currentApplicationsCurrentPage;

  @task
  *loadForNewLocation() {
    this.currentApplications.clear();
    this.currentApplications.pushObject(this.loadCurrentApplications.perform());
  }

  get applicationsLoaded() {
    return this.currentApplications.length &&
           !this.currentApplications.lastObject.isRunning;
  }

  get hasMorePages() {
    return this.currentApplications.length &&
           !this.currentApplications.lastObject.isRunning &&
           this.currentApplicationsCurrentPage.meta.page < this.currentApplicationsCurrentPage.meta.pages;
  }

  @action
  nextPage() {
    this.currentApplications.pushObject(this.loadCurrentApplications.perform());
  
}
  • hbs file

<div class="columns is-multiline dashboard__sidebar__row mb-0">
  <div class="column is-12">
  ...
  </div>
</div>

When the this.current.locationId changes, loadForNewLocation fall into loop execute. How should I solve this problem?




vendredi 9 septembre 2022

normalizeResponse must return a valid JSON API document:

Here is my Code:

Inside model:

import Model, { attr } from '@ember-data/model';

export default class TodoModel extends Model {

@attr('number') userId;

@attr('string') title;

@attr('boolean') completed;

}

Inside Adapter:

import RESTAdapter from '@ember-data/adapter/rest';

export default class TodoAdapter extends RESTAdapter {

host = 'https://ift.tt/JlnM9Eq';

}

Inside Serializer:

import RESTSerializer from '@ember-data/serializer/rest';

export default class TodoSerializer extends RESTSerializer {

normalizeResponse(store, primaryModelClass, payload, id, requestType) {

    payload={
        "todos":payload
    }

    return this._super(...arguments);

}

}

Inside Route:

import Route from '@ember/routing/route';

import { inject as service } from '@ember/service';

export default class HelloRoute extends Route {

@service store;

model() {

return this.store.findRecord('todo',1);

}

}

Error:

Error while processing route: hello Assertion Failed: normalizeResponse must return a valid JSON API document:

  • Top level of a JSON API document must be an object Error: Assertion Failed: normalizeResponse must return a valid JSON API document:

  • Top level of a JSON API document must be an object

(My point of View: The Error is coming while processing the Serializer, how to return a JSON API document from normalizeResponse function.)




The associated data from the list does not come to the content of the Proxy object of the model

I use ember-cli@3.27.0 , ember-data@3.27.1

There is a workshift.js model

import DS from 'ember-data';

export default DS.Model.extend({
  date: DS.attr(),
  timestart: DS.attr(),
  timeend: DS.attr(),

  house: DS.belongsTo('house'),
  responsible: DS.belongsTo('employee'),

  employeeOnWorkshift: DS.hasMany('employee-on-workshift'),
});

There are employee-on-workshift.js model

import DS from 'ember-data';

export default DS.Model.extend({
  workshift: DS.belongsTo('workshift'),
  account: DS.belongsTo('account'),
  employee: DS.belongsTo('employee'),
});

and employee.js model

import DS from 'ember-data';

export default DS.Model.extend({
  fio: DS.attr(),
  age: DS.attr(),
  phone: DS.attr(),
  datebirth: DS.attr(),
  telegram: DS.attr(),

  user: DS.belongsTo('people'),
  employeeOnWorkshift: DS.hasMany('employee-on-workshift'),
});

In route, I unload all the workshift and their associated employeeOnWorkshift data as an array.

import Route from './base-route';
import RSVP from 'rsvp';

export default Route.extend({
  model(params) {
    this.store.findRecord('workshift', params.id);
  },
  afterModel(models) {
    models.get('employeeOnWorkshift').forEach((employeeOnWorkshift) => {
      employeeOnWorkshift.get('employee');
      employeeOnWorkshift.get('employee.user');
    })
  }
});

Yes, I understand that loading additional models for each list item is a bad decision, but my goal is to figure out why the data is not displayed.

In the template, I'm just going through the model list and trying to get an employee.fio, but the data is empty


  

Although in the browser on the network I can see how the data of each employee for the employeeOnWorkshift list has been loaded: Requests to the backend

I checked the model e employee in the console. The Proxy object is returned there, in which, as I understand it, if isPending = false and isSettled = true, the content parameter will be filled with the Model object, but even after receiving the data, this does not happen.

Proxy {isFulfilled: false, isRejected: false, content: null, _belongsToState: {…}, _super: ƒ, …}
[[Handler]]: Object
[[Target]]: Class
  content: null
  isFulfilled: false
  isRejected: false
  _belongsToState: {key: 'employee', store: Store, originatingInternalModel: InternalModel,   modelName: 'employee'}
  _super: ƒ ()
  Symbol(INIT_FACTORY): undefined
  Symbol(OWNER): undefined
  isPending: true
  isSettled: false
  isTruthy: false
  meta: (...)
  promise: (...)
  isDestroyed: (...)
  isDestroying: (...)
  _debugContainerKey: (...)
[[Prototype]]: Class
[[IsRevoked]]: false

Please tell me what I'm doing wrong, why employee is not unloaded without crutches of this format:

    models.get('employeeOnWorkshift').forEach((model) => {
      model.employee.then(function (employee) {
        model.employee = employee;
      });
    });



mercredi 7 septembre 2022

Create progress bar from csv file in Ember.js

I'm new to Ember.js. I need to create single page application to display progress bar or gauge (they want something looks fancy) to show percent progress. The data is in csv file that will be used to display the percent progress. I'm trying to create this progress bar or gauge using Ember.js. I'm not able to find useful tutorials about using ember.js to display progress bars from csv file. I was only able to create new app using Ember-CLI and I installed ember progress-bar addon. I'm not sure how to proceed from here. If anyone can help with useful tutorials with step by step guidance or with any ideas about the best approach to create this SPA in Ember.js please.




how to render html text with as ember html inside a template?

Hi I have computed property that returns an html link with an ember action like this:

externalHtmlLink:

<a  href="#">Click Here</a>

but if I render this inside the template like this:

}

it renders the Action part as text and not as an Ember Html, and the action is never triggered. How should I render the link so the action is rendered by Ember?




lundi 5 septembre 2022

Consume Json api format in emberjs

data: [
       
    expiration-date: "2023-06-01T00:00:00"
    name: "Big Fish"
    id: "12932"
    membership-benefits: [{
            available-quantity: 0
            expiration-days: null
            expired-quantity: 0
            is-expired: false
            is-unlimited: false
            name: "Small Fish"
            status: {id: 2, name: "Active"}
            total-earned-quantity: 1
            used-quantity: 1
           }]

in model

@attr('string') name;
@attr('array') membershipBenefits;
@attr('string') expirationDate;

now when i m accessing the values :

console.log(model.name) /// Big Fish ✔️
console.log(model.expirationDate) /// 2023-06-01T00:00:00✔️
console.log(model.membershipBenefits[0].name) /// small Fish ✔️
console.log(model.membershipBenefits[0].status) ///  {id: 2, name: "Active"} ✔️
console.log(model.membershipBenefits[0].isUnlimited) /// undefined ❌
console.log(model.membershipBenefits[0].isExpired) /// undefined ❌

i am getting undefined value when i m accessing hyphenated properties of membershipBenefit array What is the correct way to access these properties??????




jeudi 1 septembre 2022

Unable to fetch id valuse in Java script

enter image description here

enter image description here

enter image description here

Hi there, I am trying to create two buttons save and update where the difference between them is the save button will save the data navigate to the back page and the update button will save the data and will stay on the same page. I am not sure where I am going wrong but I am unable to fetch the id in the if condition of Java Script. Thanks in advance.




EmberJS: Best way to handle multiple item heights in vertical collection

I am using https://github.com/html-next/vertical-collection in my emberjs project. In one of my lists I have elements with different heights and I was wondering how to handle estimateHeight

I have 3 different heights to account for, eg [100, 200, 300] I have tried estimateHeight with all 3 of these values and the add-on seems to handle everything well but Im trying to find the best way to ensure it is still performant.